Commit a7ab8ee8 by Tuomas Riihimäki

Restijuttuja, skynettijuttuja, accounteventbean poisrefaktorointi, statistiikaa …

…ja muuta huttua ihan liikaa.
1 parent 9029146c
Showing with 3301 additions and 262 deletions
package fi.codecrew.moya.beans;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.Stateless;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.enums.apps.ShopPermission;
import fi.codecrew.moya.enums.apps.SpecialPermission;
import fi.codecrew.moya.enums.apps.UserPermission;
import fi.codecrew.moya.facade.AccountEventFacade;
import fi.codecrew.moya.model.AccountEvent;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.Product;
import fi.codecrew.moya.model.ProductFlag;
import fi.codecrew.moya.model.Role;
/**
* Session Bean implementation class AccountEventBean
*/
@Stateless
@DeclareRoles({ UserPermission.S_VIEW_ACCOUNTEVENTS, SpecialPermission.S_USER })
public class AccountEventBean implements AccountEventBeanLocal {
@EJB
private AccountEventFacade accountfacade;
@EJB
private UserBeanLocal userbean;
@EJB
private LoggingBeanLocal loggingbean;
@EJB
private EventBeanLocal eventBean;
@EJB
private ProductBeanLocal prodbean;
@EJB
private PlaceBean placebean;
@EJB
private PermissionBeanLocal permbean;
private static final Logger logger = LoggerFactory.getLogger(AccountEventBean.class);
public AccountEventBean() {
super();
}
@Override
@RolesAllowed(UserPermission.S_MODIFY_ACCOUNTEVENTS)
public AccountEvent merge(AccountEvent account) {
return accountfacade.merge(account);
}
@Override
@RolesAllowed(UserPermission.S_MODIFY_ACCOUNTEVENTS)
public EventUser delete(AccountEvent account) {
AccountEvent acco = accountfacade.reload(account);
EventUser ret = acco.getUser();
ret.getAccountEvents().remove(acco);
loggingbean.logMessage(SecurityLogType.accountEvent, permbean.getCurrentUser(), "Deleting AccountEvent '", acco.getProduct().getName(), "' count: '", acco.getQuantity().toString(), "' unitprice: '", acco.getUnitPrice().toString(), "' accouser: '", acco.getUser().getUser().getLogin(), "'");
acco.getProduct().getAccountEvents().remove(acco);
acco.getUser().getAccountEvents().remove(acco);
if (acco.getBill() != null) {
acco.getBill().setAccountEvent(null);
}
accountfacade.remove(acco);
return ret;
}
@Override
public AccountEvent find(Integer id) {
return accountfacade.find(id);
}
@Override
public List<Role> getRolesFromAccountEvents(EventUser u) {
return accountfacade.findProvidedRoles(eventBean.getCurrentEvent(), u);
}
/**
* Create accountevents for the products in the parameter shopMap
*/
@Override
@RolesAllowed(ShopPermission.S_SHOP_PRODUCTS)
public void shopCash(EventUser shoppingUser, Map<Product, BigDecimal> shopMap, boolean buyInstant) {
logger.debug("Shoping cash. buyinstant {}", buyInstant);
EventUser seller = permbean.getCurrentUser();
shoppingUser = userbean.findByEventUserId(shoppingUser.getId());
BigDecimal tot = BigDecimal.ZERO;
for (Entry<Product, BigDecimal> prodentry : shopMap.entrySet()) {
// Create account event for the product.
AccountEvent ac = new AccountEvent(shoppingUser, prodentry.getKey(), prodentry.getKey().getPrice(), prodentry.getValue(), Calendar.getInstance());
ac.setSeller(seller);
accountfacade.create(ac);
if (buyInstant && prodentry.getKey().getPrice().compareTo(BigDecimal.ZERO) > 0) {
tot = tot.add(prodentry.getValue().multiply(prodentry.getKey().getPrice()));
}
if (prodentry.getKey().getProductFlags().contains(ProductFlag.RESERVE_PLACE_WHEN_BOUGHT) || prodentry.getKey().getProductFlags().contains(ProductFlag.CREATE_NEW_PLACE_WHEN_BOUGHT)) {
logger.debug("Prepaidplace");
placebean.lockPlaceProduct(shoppingUser, prodentry.getKey(), BigDecimal.ONE);
}
}
logger.debug("ShopCash price {}", tot);
if (buyInstant && tot.compareTo(BigDecimal.ZERO) > 0) {
logger.debug("Creating buy instant product!");
Product creditProd = prodbean.findCreditProduct();
AccountEvent ac = new AccountEvent(shoppingUser, creditProd, creditProd.getPrice(), tot, Calendar.getInstance());
accountfacade.create(ac);
}
userbean.mergeEventUserChanges(shoppingUser);
}
@Override
public AccountEvent markDelivered(AccountEvent e, Calendar c) {
e = accountfacade.reload(e);
if (e.getDelivered() != null)
{
throw new EJBException("AccountEvent " + e + " already marked paid!");
}
e.setDelivered(c);
return e;
}
}
......@@ -179,11 +179,13 @@ public class CardPrintBean implements CardPrintBeanLocal {
int[] white = new int[] { 255, 255, 255 };
// User nick text
// For skynett 2013
int[] nickTextColor = new int[] { 197, 220, 85 };
TextLine nickTextLine = new TextLine(nickFont);
nickTextLine.setText(user.getUser().getNick());
nickTextLine.setPosition(17.0, 195.0);
nickTextLine.setColor(white);
nickTextLine.setColor(nickTextColor);
nickTextLine.drawOn(page);
// Smaller font
......@@ -195,14 +197,14 @@ public class CardPrintBean implements CardPrintBeanLocal {
TextLine wholeNameText = new TextLine(font);
wholeNameText.setText(wholeName);
wholeNameText.setPosition(17.0, 211.0);
wholeNameText.setColor(white);
wholeNameText.setColor(nickTextColor);
wholeNameText.drawOn(page);
// Role text
TextLine roleTextLine = new TextLine(font);
roleTextLine.setText(cardTemplate.getName());
roleTextLine.setPosition(17.0, 224.0);
roleTextLine.setColor(white);
roleTextLine.setColor(nickTextColor);
roleTextLine.drawOn(page);
// Barcode
......@@ -267,8 +269,11 @@ public class CardPrintBean implements CardPrintBeanLocal {
//Color transparentWhite = new Color(255, 255, 255, 140);
//g.setColor(transparentWhite);
//g.fillRect(nickX - 20, nickY - 50, nickWidth + 40, 50);
// int[] nickTextColor = new int[] { 197, 220, 85 };
g.setColor(Color.white);
//SKynett printCOlor
Color nickColor = new Color(197, 220, 85);
g.setColor(nickColor);
g.setFont(nickfont);
g.drawString(user.getUser().getNick(), nickX, nickY);
......
......@@ -7,6 +7,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Set;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
......@@ -187,8 +188,8 @@ public class CardTemplateBean implements CardTemplateBeanLocal {
@RolesAllowed(UserPermission.S_VIEW_ALL)
public CardTemplate getUsersCardtype(EventUser user) {
List<Role> roles = userbean.localFindUsersRoles(user);
Set<Role> roles = userbean.localFindUsersRoles(user);
logger.info("Checking roles {} against {}", user, roles);
CardTemplate greatestTemplate = null;
for (Role listrole : roles) {
logger.info("Checking role {}", listrole);
......
......@@ -2,7 +2,7 @@ package fi.codecrew.moya.beans;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import javax.ejb.EJB;
......@@ -135,7 +135,7 @@ public class JaasBean implements MoyaRealmBeanRemote {
roleset.add(SpecialPermission.SUPERADMIN.name());
} else {
List<Role> usrroles = userbean.localFindUsersRoles(usr);
Set<Role> usrroles = userbean.localFindUsersRoles(usr);
for (Role role : usrroles) {
for (ApplicationPermission apperm : role.getPermissions()) {
roleset.add(apperm.getPermission().getFullName());
......
......@@ -99,8 +99,6 @@ public class PlaceBean implements PlaceBeanLocal {
@EJB
private LoggingBeanLocal loggerbean;
@EJB
private AccountEventBeanLocal acbean;
@EJB
private PlaceGroupFacade pgfacade;
@EJB
private ProductPBean productPBean;
......
......@@ -14,6 +14,7 @@ import java.util.Set;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
......@@ -22,6 +23,8 @@ import org.slf4j.LoggerFactory;
import fi.codecrew.moya.bortal.views.BillSummary;
import fi.codecrew.moya.enums.apps.ShopPermission;
import fi.codecrew.moya.enums.apps.SpecialPermission;
import fi.codecrew.moya.enums.apps.UserPermission;
import fi.codecrew.moya.facade.AccountEventFacade;
import fi.codecrew.moya.facade.BillLineFacade;
import fi.codecrew.moya.facade.DiscountFacade;
......@@ -49,7 +52,11 @@ import fi.codecrew.moya.model.Role;
ShopPermission.S_LIST_USERPRODUCTS,
ShopPermission.S_MANAGE_PRODUCTS,
ShopPermission.S_SHOP_PRODUCTS,
ShopPermission.S_SHOP_TO_OTHERS
ShopPermission.S_SHOP_TO_OTHERS,
UserPermission.S_VIEW_ACCOUNTEVENTS,
SpecialPermission.S_USER,
})
public class ProductBean implements ProductBeanLocal {
......@@ -87,7 +94,12 @@ public class ProductBean implements ProductBeanLocal {
@EJB
private ProductPBean productPBean;
@SuppressWarnings("unused")
@EJB
private LoggingBeanLocal loggingbean;
@EJB
private PlaceBean placebean;
private static final Logger logger = LoggerFactory.getLogger(ProductBean.class);
/**
......@@ -370,4 +382,96 @@ public class ProductBean implements ProductBeanLocal {
return returnProducts;
}
@Override
@RolesAllowed(UserPermission.S_MODIFY_ACCOUNTEVENTS)
public AccountEvent merge(AccountEvent account) {
return accounteventfacade.merge(account);
}
@Override
@RolesAllowed(UserPermission.S_MODIFY_ACCOUNTEVENTS)
public EventUser delete(AccountEvent account) {
AccountEvent acco = accounteventfacade.reload(account);
EventUser ret = acco.getUser();
ret.getAccountEvents().remove(acco);
loggingbean.logMessage(SecurityLogType.accountEvent, permbean.getCurrentUser(), "Deleting AccountEvent '", acco.getProduct().getName(), "' count: '", acco.getQuantity().toString(), "' unitprice: '", acco.getUnitPrice().toString(), "' accouser: '", acco.getUser().getUser().getLogin(), "'");
acco.getProduct().getAccountEvents().remove(acco);
acco.getUser().getAccountEvents().remove(acco);
if (acco.getBill() != null) {
acco.getBill().setAccountEvent(null);
}
accounteventfacade.remove(acco);
return ret;
}
@Override
public AccountEvent find(Integer id) {
return accounteventfacade.find(id);
}
@Override
public List<Role> getRolesFromAccountEvents(EventUser u) {
return accounteventfacade.findProvidedRoles(eventBean.getCurrentEvent(), u);
}
/**
* Create accountevents for the products in the parameter shopMap
*/
@Override
@RolesAllowed(ShopPermission.S_SHOP_PRODUCTS)
public void shopCash(EventUser shoppingUser, Map<Product, BigDecimal> shopMap, boolean buyInstant) {
logger.debug("Shoping cash. buyinstant {}", buyInstant);
EventUser seller = permbean.getCurrentUser();
shoppingUser = userbean.findByEventUserId(shoppingUser.getId());
BigDecimal tot = BigDecimal.ZERO;
for (Entry<Product, BigDecimal> prodentry : shopMap.entrySet()) {
// Create account event for the product.
AccountEvent ac = new AccountEvent(shoppingUser, prodentry.getKey(), prodentry.getKey().getPrice(), prodentry.getValue(), Calendar.getInstance());
ac.setSeller(seller);
accounteventfacade.create(ac);
if (buyInstant && prodentry.getKey().getPrice().compareTo(BigDecimal.ZERO) > 0) {
tot = tot.add(prodentry.getValue().multiply(prodentry.getKey().getPrice()));
}
if (prodentry.getKey().getProductFlags().contains(ProductFlag.RESERVE_PLACE_WHEN_BOUGHT) || prodentry.getKey().getProductFlags().contains(ProductFlag.CREATE_NEW_PLACE_WHEN_BOUGHT)) {
logger.debug("Prepaidplace");
placebean.lockPlaceProduct(shoppingUser, prodentry.getKey(), BigDecimal.ONE);
}
}
logger.debug("ShopCash price {}", tot);
if (buyInstant && tot.compareTo(BigDecimal.ZERO) > 0) {
logger.debug("Creating buy instant product!");
Product creditProd = findCreditProduct();
AccountEvent ac = new AccountEvent(shoppingUser, creditProd, creditProd.getPrice(), tot, Calendar.getInstance());
accounteventfacade.create(ac);
}
userbean.mergeEventUserChanges(shoppingUser);
}
@Override
public AccountEvent markDelivered(AccountEvent e, Calendar c) {
e = accounteventfacade.reload(e);
if (e.getDelivered() != null)
{
throw new EJBException("AccountEvent " + e + " already marked paid!");
}
e.setDelivered(c);
return e;
}
}
......@@ -51,7 +51,7 @@ public class ReaderBean implements ReaderBeanLocal {
private static final Logger logger = LoggerFactory.getLogger(ReaderBean.class);
@Override
public ReaderEvent checkTag(String readerIdent, String tag, String hash) {
public ReaderEvent checkTag(String readerIdent, String tag) {
Reader reader = readerfacade.findOrCreateByIdent(readerIdent);
......
......@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.PermitAll;
......@@ -113,7 +114,7 @@ public class SitePageBean implements SitePageBeanLocal {
private List<PageContent> getContentsForPage(SitePage page, Locale locale)
{
List<Role> roles = userbean.localFindUsersRoles(permbean.getCurrentUser());
Set<Role> roles = userbean.localFindUsersRoles(permbean.getCurrentUser());
List<PageContent> ret = null;
if (page != null && page.getAllowedRoles() != null) {
......
......@@ -104,9 +104,6 @@ public class UserBean implements UserBeanLocal {
private BarcodeBeanLocal barcodeBean;
@EJB
private AccountEventBeanLocal acbean;
@EJB
private PermissionBeanLocal permbean;
@EJB
private GroupMembershipFacade gmfacade;
......@@ -129,6 +126,8 @@ public class UserBean implements UserBeanLocal {
private UserApprovalFacade userApprovalFacade;
@EJB
private GameIDFacade gameIDFacade;
@EJB
private ProductBeanLocal productbean;
@Override
@RolesAllowed(UserPermission.S_VIEW_ALL)
......@@ -161,14 +160,14 @@ public class UserBean implements UserBeanLocal {
throw new EJBAccessException("Not enough rights to find roles");
}
return localFindUsersRoles(u);
return new ArrayList<Role>(localFindUsersRoles(u));
}
// private EventUser currentEventuser;
// private ArrayList<Role> currentEventuserRoles;
public ArrayList<Role> localFindUsersRoles(EventUser u) {
public Set<Role> localFindUsersRoles(EventUser u) {
// if (currentEventuser != null && u.equals(currentEventuser)) {
// logger.debug("Returnin cached eventuserroles for user {}: {}",
// currentEventuser, currentEventuserRoles);
......@@ -186,28 +185,29 @@ public class UserBean implements UserBeanLocal {
// add roles from events default role.
addRecursive(checkedRoles, event.getDefaultRole());
// add roles from accountEvents of the user
addRecursive(checkedRoles, acbean.getRolesFromAccountEvents(u));
for (GroupMembership member : gmfacade.findMemberships(u)) {
if (member != null && member.getPlaceReservation() != null)
}
// add roles from accountEvents of the user
addRecursive(checkedRoles, productbean.getRolesFromAccountEvents(u));
for (GroupMembership member : gmfacade.findMemberships(u)) {
if (member != null && member.getPlaceReservation() != null)
{
addRecursive(checkedRoles, member.getPlaceReservation().getProvidesRole());
if (member.getPlaceReservation().getProduct() != null)
{
addRecursive(checkedRoles, member.getPlaceReservation().getProvidesRole());
if (member.getPlaceReservation().getProduct() != null)
{
addRecursive(checkedRoles, member.getPlaceReservation().getProduct().getProvides());
}
addRecursive(checkedRoles, member.getPlaceReservation().getProduct().getProvides());
}
}
}
}
// currentEventuser = u;
// currentEventuserRoles = new ArrayList<Role>(checkedRoles);
// logger.debug("Returning parsed eventUser roles for user {}: {} ", u,
// currentEventuserRoles);
// return currentEventuserRoles;
return new ArrayList<Role>(checkedRoles);
return checkedRoles;
}
private static void addRecursive(Set<Role> checkedRoles, Collection<Role> roles) {
......@@ -525,37 +525,38 @@ public class UserBean implements UserBeanLocal {
eventUserFacade.create(evu);
return evu;
}
@Override
@RolesAllowed(UserPermission.S_MODIFY_OWN_GAMEIDS)
public void addGameID(TournamentGame game, String gameid) {
EventUser u = permbean.getCurrentUser();
GameID gid = new GameID();
gid.setIdentifier(gameid);
gid.setGame(game);
gid.setUser(u);
gid = gameIDFacade.create(gid);
u.getGameIDs().add(gid);
}
@Override
@RolesAllowed(UserPermission.S_MODIFY_OWN_GAMEIDS)
public void removeGameIdById(Integer gameIdId) {
GameID gi = gameIDFacade.find(gameIdId);
// In the future we may edit other peoples' gameids, leave this as a placeholder for now
// At the very least it safeguards the situation if user gets another users gameid in somehow..
if(!permbean.isCurrentUser(gi.getEventUser())) {
if (!permbean.isCurrentUser(gi.getEventUser())) {
loggerbean.logMessage(SecurityLogType.permissionDenied, permbean.getCurrentUser(), "User tried to remove GameID from another user: " + gi.getEventUser());
throw new EJBAccessException("Not enough rights to remove another users' GameIDs");
}
gi.getEventUser().getGameIDs().remove(gi);
gameIDFacade.remove(gi);
}
@Override
@RolesAllowed(UserPermission.S_VIEW_ALL_GAMEIDS)
public GameID getGameIDByGameAndUser(TournamentGame tg, EventUser user) {
......@@ -712,4 +713,20 @@ public class UserBean implements UserBeanLocal {
return ret;
}
@Override
public boolean isUserInRole(EventUser user, Integer roleId) {
Set<Role> roles = localFindUsersRoles(user);
logger.info("CHecking user {} roleid {} from roles {}, roles size{}", user, roleId, roles, roles.size());
addRecursive(roles, eventBean.getCurrentEvent().getDefaultRole());
for (Role r : roles) {
if (roleId.equals(r.getId())) {
logger.info("User {} found in role {}", user, roleId);
return true;
}
}
logger.info("User {} NOT found in role {}", user, roleId);
return false;
}
}
\ No newline at end of file
package fi.codecrew.moya.beans;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import fi.codecrew.moya.model.AccountEvent;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.Product;
import fi.codecrew.moya.model.Role;
@Local
public interface AccountEventBeanLocal {
AccountEvent merge(AccountEvent account);
EventUser delete(AccountEvent account);
AccountEvent find(Integer id);
void shopCash(EventUser shoppingUser, Map<Product, BigDecimal> shopMap, boolean buyInstant);
List<Role> getRolesFromAccountEvents(EventUser u);
AccountEvent markDelivered(AccountEvent e, Calendar c);
}
......@@ -14,6 +14,7 @@ import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.InventoryEvent;
import fi.codecrew.moya.model.Product;
import fi.codecrew.moya.model.ProductFlag;
import fi.codecrew.moya.model.Role;
@Local
public interface ProductBeanLocal {
......@@ -55,7 +56,19 @@ public interface ProductBeanLocal {
void saveInventoryEvent(InventoryEvent ie);
List<Product> findProductsForEvent();
List<Product> findPlaceProducts();
AccountEvent merge(AccountEvent account);
EventUser delete(AccountEvent account);
AccountEvent find(Integer id);
void shopCash(EventUser shoppingUser, Map<Product, BigDecimal> shopMap, boolean buyInstant);
List<Role> getRolesFromAccountEvents(EventUser u);
AccountEvent markDelivered(AccountEvent e, Calendar c);
}
......@@ -13,8 +13,6 @@ import fi.codecrew.moya.model.User;
@Local
public interface ReaderBeanLocal {
ReaderEvent checkTag(String reader, String tag, String hash);
// WAT!
// ReaderEvent assocTagToPlacecode(String tag, String readerIdent, String
// placecode) throws BortalCatchableException, PermissionDeniedException;
......@@ -41,4 +39,6 @@ public interface ReaderBeanLocal {
List<ReaderEvent> getLastReaderEvents();
ReaderEvent checkTag(String readerIdent, String tag);
}
......@@ -99,4 +99,6 @@ public interface UserBeanLocal {
GameID getGameIDByGameAndUser(TournamentGame tg, EventUser user);
boolean isUserInRole(EventUser user, Integer roleId);
}
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:map="http://java.sun.com/jsf/composite/cditools/map" xmlns:tools="http://java.sun.com/jsf/composite/cditools" xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:body>
<ui:composition template="#{sessionHandler.template}">
<ui:define name="headerdata">
<script type="text/javascript" src="#{request.contextPath}/resources/highcharts/js/highcharts.js"></script>
<script type="text/javascript" src="#{request.contextPath}/resources/script/stats.js" />
</ui:define>
<ui:define name="content">
<div id="hccontainer" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
</ui:define>
</ui:composition>
</h:body>
</html>
\ No newline at end of file
/*
Highcharts JS v3.0.7 (2013-10-24)
MooTools adapter
(c) 2010-2013 Torstein Hønsi
License: www.highcharts.com/license
*/
(function(){var e=window,h=document,f=e.MooTools.version.substring(0,3),i=f==="1.2"||f==="1.1",j=i||f==="1.3",g=e.$extend||function(){return Object.append.apply(Object,arguments)};e.HighchartsAdapter={init:function(a){var b=Fx.prototype,c=b.start,d=Fx.Morph.prototype,e=d.compute;b.start=function(b,d){var e=this.element;if(b.d)this.paths=a.init(e,e.d,this.toD);c.apply(this,arguments);return this};d.compute=function(b,c,d){var f=this.paths;if(f)this.element.attr("d",a.step(f[0],f[1],d,this.toD));else return e.apply(this,
arguments)}},adapterRun:function(a,b){if(b==="width"||b==="height")return parseInt(document.id(a).getStyle(b),10)},getScript:function(a,b){var c=h.getElementsByTagName("head")[0],d=h.createElement("script");d.type="text/javascript";d.src=a;d.onload=b;c.appendChild(d)},animate:function(a,b,c){var d=a.attr,f=c&&c.complete;if(d&&!a.setStyle)a.getStyle=a.attr,a.setStyle=function(){var a=arguments;this.attr.call(this,a[0],a[1][0])},a.$family=function(){return!0},a.getComputedStyle=function(){return a.element.getComputedStyle.apply(a.element,
arguments)};e.HighchartsAdapter.stop(a);c=new Fx.Morph(d?a:document.id(a),g({transition:Fx.Transitions.Quad.easeInOut},c));if(d)c.element=a;if(b.d)c.toD=b.d;f&&c.addEvent("complete",f);c.start(b);a.fx=c},each:function(a,b){return i?$each(a,b):Array.each(a,b)},map:function(a,b){return a.map(b)},grep:function(a,b){return a.filter(b)},inArray:function(a,b,c){return b?b.indexOf(a,c):-1},offset:function(a){a=a.getPosition();return{left:a.x,top:a.y}},extendWithEvents:function(a){a.addEvent||(a.nodeName?
document.id(a):g(a,new Events))},addEvent:function(a,b,c){typeof b==="string"&&(b==="unload"&&(b="beforeunload"),e.HighchartsAdapter.extendWithEvents(a),a.addEvent(b,c))},removeEvent:function(a,b,c){typeof a!=="string"&&a.addEvent&&(b?(b==="unload"&&(b="beforeunload"),c?a.removeEvent(b,c):a.removeEvents&&a.removeEvents(b)):a.removeEvents())},fireEvent:function(a,b,c,d){b={type:b,target:a};b=j?new Event(b):new DOMEvent(b);b=g(b,c);if(!b.target&&b.event)b.target=b.event.target;b.preventDefault=function(){d=
null};a.fireEvent&&a.fireEvent(b.type,b);d&&d(b)},washMouseEvent:function(a){if(a.page)a.pageX=a.page.x,a.pageY=a.page.y;return a},stop:function(a){a.fx&&a.fx.cancel()}}})();
/**
* @license Highcharts JS v3.0.7 (2013-10-24)
* MooTools adapter
*
* (c) 2010-2013 Torstein Hønsi
*
* License: www.highcharts.com/license
*/
// JSLint options:
/*global Fx, $, $extend, $each, $merge, Events, Event, DOMEvent */
(function () {
var win = window,
doc = document,
mooVersion = win.MooTools.version.substring(0, 3), // Get the first three characters of the version number
legacy = mooVersion === '1.2' || mooVersion === '1.1', // 1.1 && 1.2 considered legacy, 1.3 is not.
legacyEvent = legacy || mooVersion === '1.3', // In versions 1.1 - 1.3 the event class is named Event, in newer versions it is named DOMEvent.
$extend = win.$extend || function () {
return Object.append.apply(Object, arguments);
};
win.HighchartsAdapter = {
/**
* Initialize the adapter. This is run once as Highcharts is first run.
* @param {Object} pathAnim The helper object to do animations across adapters.
*/
init: function (pathAnim) {
var fxProto = Fx.prototype,
fxStart = fxProto.start,
morphProto = Fx.Morph.prototype,
morphCompute = morphProto.compute;
// override Fx.start to allow animation of SVG element wrappers
/*jslint unparam: true*//* allow unused parameters in fx functions */
fxProto.start = function (from, to) {
var fx = this,
elem = fx.element;
// special for animating paths
if (from.d) {
//this.fromD = this.element.d.split(' ');
fx.paths = pathAnim.init(
elem,
elem.d,
fx.toD
);
}
fxStart.apply(fx, arguments);
return this; // chainable
};
// override Fx.step to allow animation of SVG element wrappers
morphProto.compute = function (from, to, delta) {
var fx = this,
paths = fx.paths;
if (paths) {
fx.element.attr(
'd',
pathAnim.step(paths[0], paths[1], delta, fx.toD)
);
} else {
return morphCompute.apply(fx, arguments);
}
};
/*jslint unparam: false*/
},
/**
* Run a general method on the framework, following jQuery syntax
* @param {Object} el The HTML element
* @param {String} method Which method to run on the wrapped element
*/
adapterRun: function (el, method) {
// This currently works for getting inner width and height. If adding
// more methods later, we need a conditional implementation for each.
if (method === 'width' || method === 'height') {
return parseInt(document.id(el).getStyle(method), 10);
}
},
/**
* Downloads a script and executes a callback when done.
* @param {String} scriptLocation
* @param {Function} callback
*/
getScript: function (scriptLocation, callback) {
// We cannot assume that Assets class from mootools-more is available so instead insert a script tag to download script.
var head = doc.getElementsByTagName('head')[0];
var script = doc.createElement('script');
script.type = 'text/javascript';
script.src = scriptLocation;
script.onload = callback;
head.appendChild(script);
},
/**
* Animate a HTML element or SVG element wrapper
* @param {Object} el
* @param {Object} params
* @param {Object} options jQuery-like animation options: duration, easing, callback
*/
animate: function (el, params, options) {
var isSVGElement = el.attr,
effect,
complete = options && options.complete;
if (isSVGElement && !el.setStyle) {
// add setStyle and getStyle methods for internal use in Moo
el.getStyle = el.attr;
el.setStyle = function () { // property value is given as array in Moo - break it down
var args = arguments;
this.attr.call(this, args[0], args[1][0]);
};
// dirty hack to trick Moo into handling el as an element wrapper
el.$family = function () { return true; };
el.getComputedStyle = function () {
return el.element.getComputedStyle.apply(el.element, arguments);
};
}
// stop running animations
win.HighchartsAdapter.stop(el);
// define and run the effect
effect = new Fx.Morph(
isSVGElement ? el : document.id(el),
$extend({
transition: Fx.Transitions.Quad.easeInOut
}, options)
);
// Make sure that the element reference is set when animating svg elements
if (isSVGElement) {
effect.element = el;
}
// special treatment for paths
if (params.d) {
effect.toD = params.d;
}
// jQuery-like events
if (complete) {
effect.addEvent('complete', complete);
}
// run
effect.start(params);
// record for use in stop method
el.fx = effect;
},
/**
* MooTool's each function
*
*/
each: function (arr, fn) {
return legacy ?
$each(arr, fn) :
Array.each(arr, fn);
},
/**
* Map an array
* @param {Array} arr
* @param {Function} fn
*/
map: function (arr, fn) {
return arr.map(fn);
},
/**
* Grep or filter an array
* @param {Array} arr
* @param {Function} fn
*/
grep: function (arr, fn) {
return arr.filter(fn);
},
/**
* Return the index of an item in an array, or -1 if not matched
*/
inArray: function (item, arr, from) {
return arr ? arr.indexOf(item, from) : -1;
},
/**
* Get the offset of an element relative to the top left corner of the web page
*/
offset: function (el) {
var offsets = el.getPosition(); // #1496
return {
left: offsets.x,
top: offsets.y
};
},
/**
* Extends an object with Events, if its not done
*/
extendWithEvents: function (el) {
// if the addEvent method is not defined, el is a custom Highcharts object
// like series or point
if (!el.addEvent) {
if (el.nodeName) {
el = document.id(el); // a dynamically generated node
} else {
$extend(el, new Events()); // a custom object
}
}
},
/**
* Add an event listener
* @param {Object} el HTML element or custom object
* @param {String} type Event type
* @param {Function} fn Event handler
*/
addEvent: function (el, type, fn) {
if (typeof type === 'string') { // chart broke due to el being string, type function
if (type === 'unload') { // Moo self destructs before custom unload events
type = 'beforeunload';
}
win.HighchartsAdapter.extendWithEvents(el);
el.addEvent(type, fn);
}
},
removeEvent: function (el, type, fn) {
if (typeof el === 'string') {
// el.removeEvents below apperantly calls this method again. Do not quite understand why, so for now just bail out.
return;
}
if (el.addEvent) { // If el doesn't have an addEvent method, there are no events to remove
if (type) {
if (type === 'unload') { // Moo self destructs before custom unload events
type = 'beforeunload';
}
if (fn) {
el.removeEvent(type, fn);
} else if (el.removeEvents) { // #958
el.removeEvents(type);
}
} else {
el.removeEvents();
}
}
},
fireEvent: function (el, event, eventArguments, defaultFunction) {
var eventArgs = {
type: event,
target: el
};
// create an event object that keeps all functions
event = legacyEvent ? new Event(eventArgs) : new DOMEvent(eventArgs);
event = $extend(event, eventArguments);
// When running an event on the Chart.prototype, MooTools nests the target in event.event
if (!event.target && event.event) {
event.target = event.event.target;
}
// override the preventDefault function to be able to use
// this for custom events
event.preventDefault = function () {
defaultFunction = null;
};
// if fireEvent is not available on the object, there hasn't been added
// any events to it above
if (el.fireEvent) {
el.fireEvent(event.type, event);
}
// fire the default if it is passed and it is not prevented above
if (defaultFunction) {
defaultFunction(event);
}
},
/**
* Set back e.pageX and e.pageY that MooTools has abstracted away. #1165, #1346.
*/
washMouseEvent: function (e) {
if (e.page) {
e.pageX = e.page.x;
e.pageY = e.page.y;
}
return e;
},
/**
* Stop running animations on the object
*/
stop: function (el) {
if (el.fx) {
el.fx.cancel();
}
}
};
}());
/*
Highcharts JS v3.0.7 (2013-10-24)
Prototype adapter
@author Michael Nelson, Torstein Hønsi.
Feel free to use and modify this script.
Highcharts license: www.highcharts.com/license.
*/
var HighchartsAdapter=function(){var f=typeof Effect!=="undefined";return{init:function(a){if(f)Effect.HighchartsTransition=Class.create(Effect.Base,{initialize:function(b,c,d,g){var e;this.element=b;this.key=c;e=b.attr?b.attr(c):$(b).getStyle(c);if(c==="d")this.paths=a.init(b,b.d,d),this.toD=d,e=0,d=1;this.start(Object.extend(g||{},{from:e,to:d,attribute:c}))},setup:function(){HighchartsAdapter._extend(this.element);if(!this.element._highchart_animation)this.element._highchart_animation={};this.element._highchart_animation[this.key]=
this},update:function(b){var c=this.paths,d=this.element;c&&(b=a.step(c[0],c[1],b,this.toD));d.attr?d.element&&d.attr(this.options.attribute,b):(c={},c[this.options.attribute]=b,$(d).setStyle(c))},finish:function(){this.element&&this.element._highchart_animation&&delete this.element._highchart_animation[this.key]}})},adapterRun:function(a,b){return parseInt($(a).getStyle(b),10)},getScript:function(a,b){var c=$$("head")[0];c&&c.appendChild((new Element("script",{type:"text/javascript",src:a})).observe("load",
b))},addNS:function(a){var b=/^(?:click|mouse(?:down|up|over|move|out))$/;return/^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/.test(a)||b.test(a)?a:"h:"+a},addEvent:function(a,b,c){a.addEventListener||a.attachEvent?Event.observe($(a),HighchartsAdapter.addNS(b),c):(HighchartsAdapter._extend(a),a._highcharts_observe(b,c))},animate:function(a,b,c){var d,c=c||{};c.delay=0;c.duration=(c.duration||500)/1E3;c.afterFinish=c.complete;if(f)for(d in b)new Effect.HighchartsTransition($(a),
d,b[d],c);else{if(a.attr)for(d in b)a.attr(d,b[d]);c.complete&&c.complete()}a.attr||$(a).setStyle(b)},stop:function(a){var b;if(a._highcharts_extended&&a._highchart_animation)for(b in a._highchart_animation)a._highchart_animation[b].cancel()},each:function(a,b){$A(a).each(b)},inArray:function(a,b,c){return b?b.indexOf(a,c):-1},offset:function(a){return $(a).cumulativeOffset()},fireEvent:function(a,b,c,d){a.fire?a.fire(HighchartsAdapter.addNS(b),c):a._highcharts_extended&&(c=c||{},a._highcharts_fire(b,
c));c&&c.defaultPrevented&&(d=null);d&&d(c)},removeEvent:function(a,b,c){$(a).stopObserving&&(b&&(b=HighchartsAdapter.addNS(b)),$(a).stopObserving(b,c));window===a?Event.stopObserving(a,b,c):(HighchartsAdapter._extend(a),a._highcharts_stop_observing(b,c))},washMouseEvent:function(a){return a},grep:function(a,b){return a.findAll(b)},map:function(a,b){return a.map(b)},_extend:function(a){a._highcharts_extended||Object.extend(a,{_highchart_events:{},_highchart_animation:null,_highcharts_extended:!0,
_highcharts_observe:function(b,a){this._highchart_events[b]=[this._highchart_events[b],a].compact().flatten()},_highcharts_stop_observing:function(b,a){b?a?this._highchart_events[b]=[this._highchart_events[b]].compact().flatten().without(a):delete this._highchart_events[b]:this._highchart_events={}},_highcharts_fire:function(a,c){var d=this;(this._highchart_events[a]||[]).each(function(a){if(!c.stopped)c.preventDefault=function(){c.defaultPrevented=!0},c.target=d,a.bind(this)(c)===!1&&c.preventDefault()}.bind(this))}})}}}();
/**
* @license Highcharts JS v3.0.7 (2013-10-24)
* Prototype adapter
*
* @author Michael Nelson, Torstein Hønsi.
*
* Feel free to use and modify this script.
* Highcharts license: www.highcharts.com/license.
*/
// JSLint options:
/*global Effect, Class, Event, Element, $, $$, $A */
// Adapter interface between prototype and the Highcharts charting library
var HighchartsAdapter = (function () {
var hasEffect = typeof Effect !== 'undefined';
return {
/**
* Initialize the adapter. This is run once as Highcharts is first run.
* @param {Object} pathAnim The helper object to do animations across adapters.
*/
init: function (pathAnim) {
if (hasEffect) {
/**
* Animation for Highcharts SVG element wrappers only
* @param {Object} element
* @param {Object} attribute
* @param {Object} to
* @param {Object} options
*/
Effect.HighchartsTransition = Class.create(Effect.Base, {
initialize: function (element, attr, to, options) {
var from,
opts;
this.element = element;
this.key = attr;
from = element.attr ? element.attr(attr) : $(element).getStyle(attr);
// special treatment for paths
if (attr === 'd') {
this.paths = pathAnim.init(
element,
element.d,
to
);
this.toD = to;
// fake values in order to read relative position as a float in update
from = 0;
to = 1;
}
opts = Object.extend((options || {}), {
from: from,
to: to,
attribute: attr
});
this.start(opts);
},
setup: function () {
HighchartsAdapter._extend(this.element);
// If this is the first animation on this object, create the _highcharts_animation helper that
// contain pointers to the animation objects.
if (!this.element._highchart_animation) {
this.element._highchart_animation = {};
}
// Store a reference to this animation instance.
this.element._highchart_animation[this.key] = this;
},
update: function (position) {
var paths = this.paths,
element = this.element,
obj;
if (paths) {
position = pathAnim.step(paths[0], paths[1], position, this.toD);
}
if (element.attr) { // SVGElement
if (element.element) { // If not, it has been destroyed (#1405)
element.attr(this.options.attribute, position);
}
} else { // HTML, #409
obj = {};
obj[this.options.attribute] = position;
$(element).setStyle(obj);
}
},
finish: function () {
// Delete the property that holds this animation now that it is finished.
// Both canceled animations and complete ones gets a 'finish' call.
if (this.element && this.element._highchart_animation) { // #1405
delete this.element._highchart_animation[this.key];
}
}
});
}
},
/**
* Run a general method on the framework, following jQuery syntax
* @param {Object} el The HTML element
* @param {String} method Which method to run on the wrapped element
*/
adapterRun: function (el, method) {
// This currently works for getting inner width and height. If adding
// more methods later, we need a conditional implementation for each.
return parseInt($(el).getStyle(method), 10);
},
/**
* Downloads a script and executes a callback when done.
* @param {String} scriptLocation
* @param {Function} callback
*/
getScript: function (scriptLocation, callback) {
var head = $$('head')[0]; // Returns an array, so pick the first element.
if (head) {
// Append a new 'script' element, set its type and src attributes, add a 'load' handler that calls the callback
head.appendChild(new Element('script', { type: 'text/javascript', src: scriptLocation}).observe('load', callback));
}
},
/**
* Custom events in prototype needs to be namespaced. This method adds a namespace 'h:' in front of
* events that are not recognized as native.
*/
addNS: function (eventName) {
var HTMLEvents = /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
MouseEvents = /^(?:click|mouse(?:down|up|over|move|out))$/;
return (HTMLEvents.test(eventName) || MouseEvents.test(eventName)) ?
eventName :
'h:' + eventName;
},
// el needs an event to be attached. el is not necessarily a dom element
addEvent: function (el, event, fn) {
if (el.addEventListener || el.attachEvent) {
Event.observe($(el), HighchartsAdapter.addNS(event), fn);
} else {
HighchartsAdapter._extend(el);
el._highcharts_observe(event, fn);
}
},
// motion makes things pretty. use it if effects is loaded, if not... still get to the end result.
animate: function (el, params, options) {
var key,
fx;
// default options
options = options || {};
options.delay = 0;
options.duration = (options.duration || 500) / 1000;
options.afterFinish = options.complete;
// animate wrappers and DOM elements
if (hasEffect) {
for (key in params) {
// The fx variable is seemingly thrown away here, but the Effect.setup will add itself to the _highcharts_animation object
// on the element itself so its not really lost.
fx = new Effect.HighchartsTransition($(el), key, params[key], options);
}
} else {
if (el.attr) { // #409 without effects
for (key in params) {
el.attr(key, params[key]);
}
}
if (options.complete) {
options.complete();
}
}
if (!el.attr) { // HTML element, #409
$(el).setStyle(params);
}
},
// this only occurs in higcharts 2.0+
stop: function (el) {
var key;
if (el._highcharts_extended && el._highchart_animation) {
for (key in el._highchart_animation) {
// Cancel the animation
// The 'finish' function in the Effect object will remove the reference
el._highchart_animation[key].cancel();
}
}
},
// um.. each
each: function (arr, fn) {
$A(arr).each(fn);
},
inArray: function (item, arr, from) {
return arr ? arr.indexOf(item, from) : -1;
},
/**
* Get the cumulative offset relative to the top left of the page. This method, unlike its
* jQuery and MooTools counterpart, still suffers from issue #208 regarding the position
* of a chart within a fixed container.
*/
offset: function (el) {
return $(el).cumulativeOffset();
},
// fire an event based on an event name (event) and an object (el).
// again, el may not be a dom element
fireEvent: function (el, event, eventArguments, defaultFunction) {
if (el.fire) {
el.fire(HighchartsAdapter.addNS(event), eventArguments);
} else if (el._highcharts_extended) {
eventArguments = eventArguments || {};
el._highcharts_fire(event, eventArguments);
}
if (eventArguments && eventArguments.defaultPrevented) {
defaultFunction = null;
}
if (defaultFunction) {
defaultFunction(eventArguments);
}
},
removeEvent: function (el, event, handler) {
if ($(el).stopObserving) {
if (event) {
event = HighchartsAdapter.addNS(event);
}
$(el).stopObserving(event, handler);
} if (window === el) {
Event.stopObserving(el, event, handler);
} else {
HighchartsAdapter._extend(el);
el._highcharts_stop_observing(event, handler);
}
},
washMouseEvent: function (e) {
return e;
},
// um, grep
grep: function (arr, fn) {
return arr.findAll(fn);
},
// um, map
map: function (arr, fn) {
return arr.map(fn);
},
// extend an object to handle highchart events (highchart objects, not svg elements).
// this is a very simple way of handling events but whatever, it works (i think)
_extend: function (object) {
if (!object._highcharts_extended) {
Object.extend(object, {
_highchart_events: {},
_highchart_animation: null,
_highcharts_extended: true,
_highcharts_observe: function (name, fn) {
this._highchart_events[name] = [this._highchart_events[name], fn].compact().flatten();
},
_highcharts_stop_observing: function (name, fn) {
if (name) {
if (fn) {
this._highchart_events[name] = [this._highchart_events[name]].compact().flatten().without(fn);
} else {
delete this._highchart_events[name];
}
} else {
this._highchart_events = {};
}
},
_highcharts_fire: function (name, args) {
var target = this;
(this._highchart_events[name] || []).each(function (fn) {
// args is never null here
if (args.stopped) {
return; // "throw $break" wasn't working. i think because of the scope of 'this'.
}
// Attach a simple preventDefault function to skip default handler if called
args.preventDefault = function () {
args.defaultPrevented = true;
};
args.target = target;
// If the event handler return false, prevent the default handler from executing
if (fn.bind(this)(args) === false) {
args.preventDefault();
}
}
.bind(this));
}
});
}
}
};
}());
/*
Highcharts JS v3.0.7 (2013-10-24)
Standalone Highcharts Framework
License: MIT License
*/
var HighchartsAdapter=function(){function o(c){function a(a,b,d){a.removeEventListener(b,d,!1)}function d(a,b,d){d=a.HCProxiedMethods[d.toString()];a.detachEvent("on"+b,d)}function b(b,c){var f=b.HCEvents,i,g,k,j;if(b.removeEventListener)i=a;else if(b.attachEvent)i=d;else return;c?(g={},g[c]=!0):g=f;for(j in g)if(f[j])for(k=f[j].length;k--;)i(b,j,f[j][k])}c.HCExtended||Highcharts.extend(c,{HCExtended:!0,HCEvents:{},bind:function(b,a){var d=this,c=this.HCEvents,g;if(d.addEventListener)d.addEventListener(b,
a,!1);else if(d.attachEvent){g=function(b){a.call(d,b)};if(!d.HCProxiedMethods)d.HCProxiedMethods={};d.HCProxiedMethods[a.toString()]=g;d.attachEvent("on"+b,g)}c[b]===r&&(c[b]=[]);c[b].push(a)},unbind:function(c,h){var f,i;c?(f=this.HCEvents[c]||[],h?(i=HighchartsAdapter.inArray(h,f),i>-1&&(f.splice(i,1),this.HCEvents[c]=f),this.removeEventListener?a(this,c,h):this.attachEvent&&d(this,c,h)):(b(this,c),this.HCEvents[c]=[])):(b(this),this.HCEvents={})},trigger:function(b,a){var d=this.HCEvents[b]||
[],c=d.length,g,k,j;k=function(){a.defaultPrevented=!0};for(g=0;g<c;g++){j=d[g];if(a.stopped)break;a.preventDefault=k;a.target=this;a.type=b;j.call(this,a)===!1&&a.preventDefault()}}});return c}var r,l=document,p=[],m=[],q,n;Math.easeInOutSine=function(c,a,d,b){return-d/2*(Math.cos(Math.PI*c/b)-1)+a};return{init:function(c){if(!l.defaultView)this._getStyle=function(a,d){var b;return a.style[d]?a.style[d]:(d==="opacity"&&(d="filter"),b=a.currentStyle[d.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()})],
d==="filter"&&(b=b.replace(/alpha\(opacity=([0-9]+)\)/,function(b,a){return a/100})),b===""?1:b)},this.adapterRun=function(a,d){var b={width:"clientWidth",height:"clientHeight"}[d];if(b)return a.style.zoom=1,a[b]-2*parseInt(HighchartsAdapter._getStyle(a,"padding"),10)};if(!Array.prototype.forEach)this.each=function(a,d){for(var b=0,c=a.length;b<c;b++)if(d.call(a[b],a[b],b,a)===!1)return b};if(!Array.prototype.indexOf)this.inArray=function(a,d){var b,c=0;if(d)for(b=d.length;c<b;c++)if(d[c]===a)return c;
return-1};if(!Array.prototype.filter)this.grep=function(a,d){for(var b=[],c=0,h=a.length;c<h;c++)d(a[c],c)&&b.push(a[c]);return b};n=function(a,c,b){this.options=c;this.elem=a;this.prop=b};n.prototype={update:function(){var a;a=this.paths;var d=this.elem,b=d.element;a&&b?d.attr("d",c.step(a[0],a[1],this.now,this.toD)):d.attr?b&&d.attr(this.prop,this.now):(a={},a[d]=this.now+this.unit,Highcharts.css(d,a));this.options.step&&this.options.step.call(this.elem,this.now,this)},custom:function(a,c,b){var e=
this,h=function(a){return e.step(a)},f;this.startTime=+new Date;this.start=a;this.end=c;this.unit=b;this.now=this.start;this.pos=this.state=0;h.elem=this.elem;h()&&m.push(h)===1&&(q=setInterval(function(){for(f=0;f<m.length;f++)m[f]()||m.splice(f--,1);m.length||clearInterval(q)},13))},step:function(a){var c=+new Date,b;b=this.options;var e;if(this.elem.stopAnimation)b=!1;else if(a||c>=b.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();a=this.options.curAnim[this.prop]=
!0;for(e in b.curAnim)b.curAnim[e]!==!0&&(a=!1);a&&b.complete&&b.complete.call(this.elem);b=!1}else e=c-this.startTime,this.state=e/b.duration,this.pos=b.easing(e,0,1,b.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update(),b=!0;return b}};this.animate=function(a,d,b){var e,h="",f,i,g;a.stopAnimation=!1;if(typeof b!=="object"||b===null)e=arguments,b={duration:e[2],easing:e[3],complete:e[4]};if(typeof b.duration!=="number")b.duration=400;b.easing=Math[b.easing]||Math.easeInOutSine;
b.curAnim=Highcharts.extend({},d);for(g in d)i=new n(a,b,g),f=null,g==="d"?(i.paths=c.init(a,a.d,d.d),i.toD=d.d,e=0,f=1):a.attr?e=a.attr(g):(e=parseFloat(HighchartsAdapter._getStyle(a,g))||0,g!=="opacity"&&(h="px")),f||(f=parseFloat(d[g])),i.custom(e,f,h)}},_getStyle:function(c,a){return window.getComputedStyle(c).getPropertyValue(a)},getScript:function(c,a){var d=l.getElementsByTagName("head")[0],b=l.createElement("script");b.type="text/javascript";b.src=c;b.onload=a;d.appendChild(b)},inArray:function(c,
a){return a.indexOf?a.indexOf(c):p.indexOf.call(a,c)},adapterRun:function(c,a){return parseInt(HighchartsAdapter._getStyle(c,a),10)},grep:function(c,a){return p.filter.call(c,a)},map:function(c,a){for(var d=[],b=0,e=c.length;b<e;b++)d[b]=a.call(c[b],c[b],b,c);return d},offset:function(c){for(var a=0,d=0;c;)a+=c.offsetLeft,d+=c.offsetTop,c=c.offsetParent;return{left:a,top:d}},addEvent:function(c,a,d){o(c).bind(a,d)},removeEvent:function(c,a,d){o(c).unbind(a,d)},fireEvent:function(c,a,d,b){var e;l.createEvent&&
(c.dispatchEvent||c.fireEvent)?(e=l.createEvent("Events"),e.initEvent(a,!0,!0),e.target=c,Highcharts.extend(e,d),c.dispatchEvent?c.dispatchEvent(e):c.fireEvent(a,e)):c.HCExtended===!0&&(d=d||{},c.trigger(a,d));d&&d.defaultPrevented&&(b=null);b&&b(d)},washMouseEvent:function(c){return c},stop:function(c){c.stopAnimation=!0},each:function(c,a){return Array.prototype.forEach.call(c,a)}}}();
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
(function(i,C){function m(a){return typeof a==="number"}function n(a){return a!==D&&a!==null}var D,p,r,s=i.Chart,t=i.extend,z=i.each;r=["path","rect","circle"];p={top:0,left:0,center:0.5,middle:0.5,bottom:1,right:1};var u=C.inArray,A=i.merge,B=function(){this.init.apply(this,arguments)};B.prototype={init:function(a,d){var c=d.shape&&d.shape.type;this.chart=a;var b,f;f={xAxis:0,yAxis:0,title:{style:{},text:"",x:0,y:0},shape:{params:{stroke:"#000000",fill:"transparent",strokeWidth:2}}};b={circle:{params:{x:0,
y:0}}};if(b[c])f.shape=A(f.shape,b[c]);this.options=A({},f,d)},render:function(a){var d=this.chart,c=this.chart.renderer,b=this.group,f=this.title,e=this.shape,h=this.options,i=h.title,l=h.shape;if(!b)b=this.group=c.g();if(!e&&l&&u(l.type,r)!==-1)e=this.shape=c[h.shape.type](l.params),e.add(b);if(!f&&i)f=this.title=c.label(i),f.add(b);b.add(d.annotations.group);this.linkObjects();a!==!1&&this.redraw()},redraw:function(){var a=this.options,d=this.chart,c=this.group,b=this.title,f=this.shape,e=this.linkedObject,
h=d.xAxis[a.xAxis],v=d.yAxis[a.yAxis],l=a.width,w=a.height,x=p[a.anchorY],y=p[a.anchorX],j,o,g,q;if(e)j=e instanceof i.Point?"point":e instanceof i.Series?"series":null,j==="point"?(a.xValue=e.x,a.yValue=e.y,o=e.series):j==="series"&&(o=e),c.visibility!==o.group.visibility&&c.attr({visibility:o.group.visibility});e=n(a.xValue)?h.toPixels(a.xValue+h.minPointOffset)-h.minPixelPadding:a.x;j=n(a.yValue)?v.toPixels(a.yValue):a.y;if(!isNaN(e)&&!isNaN(j)&&m(e)&&m(j)){b&&(b.attr(a.title),b.css(a.title.style));
if(f){b=t({},a.shape.params);if(a.units==="values"){for(g in b)u(g,["width","x"])>-1?b[g]=h.translate(b[g]):u(g,["height","y"])>-1&&(b[g]=v.translate(b[g]));b.width&&(b.width-=h.toPixels(0)-h.left);b.x&&(b.x+=h.minPixelPadding);if(a.shape.type==="path"){g=b.d;o=e;for(var r=j,s=g.length,k=0;k<s;)typeof g[k]==="number"&&typeof g[k+1]==="number"?(g[k]=h.toPixels(g[k])-o,g[k+1]=v.toPixels(g[k+1])-r,k+=2):k+=1}}a.shape.type==="circle"&&(b.x+=b.r,b.y+=b.r);f.attr(b)}c.bBox=null;if(!m(l))q=c.getBBox(),l=
q.width;if(!m(w))q||(q=c.getBBox()),w=q.height;if(!m(y))y=p.center;if(!m(x))x=p.center;e-=l*y;j-=w*x;d.animation&&n(c.translateX)&&n(c.translateY)?c.animate({translateX:e,translateY:j}):c.translate(e,j)}},destroy:function(){var a=this,d=this.chart.annotations.allItems,c=d.indexOf(a);c>-1&&d.splice(c,1);z(["title","shape","group"],function(b){a[b]&&(a[b].destroy(),a[b]=null)});a.group=a.title=a.shape=a.chart=a.options=null},update:function(a,d){t(this.options,a);this.linkObjects();this.render(d)},
linkObjects:function(){var a=this.chart,d=this.linkedObject,c=d&&(d.id||d.options.id),b=this.options.linkedTo;if(n(b)){if(!n(d)||b!==c)this.linkedObject=a.get(b)}else this.linkedObject=null}};t(s.prototype,{annotations:{add:function(a,d){var c=this.allItems,b=this.chart,f,e;Object.prototype.toString.call(a)==="[object Array]"||(a=[a]);for(e=a.length;e--;)f=new B(b,a[e]),c.push(f),f.render(d)},redraw:function(){z(this.allItems,function(a){a.redraw()})}}});s.prototype.callbacks.push(function(a){var d=
a.options.annotations,c;c=a.renderer.g("annotations");c.attr({zIndex:7});c.add();a.annotations.allItems=[];a.annotations.chart=a;a.annotations.group=c;Object.prototype.toString.call(d)==="[object Array]"&&d.length>0&&a.annotations.add(a.options.annotations);i.addEvent(a,"redraw",function(){a.annotations.redraw()})})})(Highcharts,HighchartsAdapter);
(function (Highcharts, HighchartsAdapter) {
var UNDEFINED,
ALIGN_FACTOR,
ALLOWED_SHAPES,
Chart = Highcharts.Chart,
extend = Highcharts.extend,
each = Highcharts.each;
ALLOWED_SHAPES = ["path", "rect", "circle"];
ALIGN_FACTOR = {
top: 0,
left: 0,
center: 0.5,
middle: 0.5,
bottom: 1,
right: 1
};
// Highcharts helper methods
var inArray = HighchartsAdapter.inArray,
merge = Highcharts.merge;
function defaultOptions(shapeType) {
var shapeOptions,
options;
options = {
xAxis: 0,
yAxis: 0,
title: {
style: {},
text: "",
x: 0,
y: 0
},
shape: {
params: {
stroke: "#000000",
fill: "transparent",
strokeWidth: 2
}
}
};
shapeOptions = {
circle: {
params: {
x: 0,
y: 0
}
}
};
if (shapeOptions[shapeType]) {
options.shape = merge(options.shape, shapeOptions[shapeType]);
}
return options;
}
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
function isNumber(n) {
return typeof n === 'number';
}
function defined(obj) {
return obj !== UNDEFINED && obj !== null;
}
function translatePath(d, xAxis, yAxis, xOffset, yOffset) {
var len = d.length,
i = 0;
while (i < len) {
if (typeof d[i] === 'number' && typeof d[i + 1] === 'number') {
d[i] = xAxis.toPixels(d[i]) - xOffset;
d[i + 1] = yAxis.toPixels(d[i + 1]) - yOffset;
i += 2;
} else {
i += 1;
}
}
return d;
}
// Define annotation prototype
var Annotation = function () {
this.init.apply(this, arguments);
};
Annotation.prototype = {
/*
* Initialize the annotation
*/
init: function (chart, options) {
var shapeType = options.shape && options.shape.type;
this.chart = chart;
this.options = merge({}, defaultOptions(shapeType), options);
},
/*
* Render the annotation
*/
render: function (redraw) {
var annotation = this,
chart = this.chart,
renderer = annotation.chart.renderer,
group = annotation.group,
title = annotation.title,
shape = annotation.shape,
options = annotation.options,
titleOptions = options.title,
shapeOptions = options.shape;
if (!group) {
group = annotation.group = renderer.g();
}
if (!shape && shapeOptions && inArray(shapeOptions.type, ALLOWED_SHAPES) !== -1) {
shape = annotation.shape = renderer[options.shape.type](shapeOptions.params);
shape.add(group);
}
if (!title && titleOptions) {
title = annotation.title = renderer.label(titleOptions);
title.add(group);
}
group.add(chart.annotations.group);
// link annotations to point or series
annotation.linkObjects();
if (redraw !== false) {
annotation.redraw();
}
},
/*
* Redraw the annotation title or shape after options update
*/
redraw: function () {
var options = this.options,
chart = this.chart,
group = this.group,
title = this.title,
shape = this.shape,
linkedTo = this.linkedObject,
xAxis = chart.xAxis[options.xAxis],
yAxis = chart.yAxis[options.yAxis],
width = options.width,
height = options.height,
anchorY = ALIGN_FACTOR[options.anchorY],
anchorX = ALIGN_FACTOR[options.anchorX],
resetBBox = false,
shapeParams,
linkType,
series,
param,
bbox,
x,
y;
if (linkedTo) {
linkType = (linkedTo instanceof Highcharts.Point) ? 'point' :
(linkedTo instanceof Highcharts.Series) ? 'series' : null;
if (linkType === 'point') {
options.xValue = linkedTo.x;
options.yValue = linkedTo.y;
series = linkedTo.series;
} else if (linkType === 'series') {
series = linkedTo;
}
if (group.visibility !== series.group.visibility) {
group.attr({
visibility: series.group.visibility
});
}
}
// Based on given options find annotation pixel position
x = (defined(options.xValue) ? xAxis.toPixels(options.xValue + xAxis.minPointOffset) - xAxis.minPixelPadding : options.x);
y = defined(options.yValue) ? yAxis.toPixels(options.yValue) : options.y;
if (isNaN(x) || isNaN(y) || !isNumber(x) || !isNumber(y)) {
return;
}
if (title) {
title.attr(options.title);
title.css(options.title.style);
resetBBox = true;
}
if (shape) {
shapeParams = extend({}, options.shape.params);
if (options.units === 'values') {
for (param in shapeParams) {
if (inArray(param, ['width', 'x']) > -1) {
shapeParams[param] = xAxis.translate(shapeParams[param]);
} else if (inArray(param, ['height', 'y']) > -1) {
shapeParams[param] = yAxis.translate(shapeParams[param]);
}
}
if (shapeParams.width) {
shapeParams.width -= xAxis.toPixels(0) - xAxis.left;
}
if (shapeParams.x) {
shapeParams.x += xAxis.minPixelPadding;
}
if (options.shape.type === 'path') {
translatePath(shapeParams.d, xAxis, yAxis, x, y);
}
}
// move the center of the circle to shape x/y
if (options.shape.type === 'circle') {
shapeParams.x += shapeParams.r;
shapeParams.y += shapeParams.r;
}
resetBBox = true;
shape.attr(shapeParams);
}
group.bBox = null;
// If annotation width or height is not defined in options use bounding box size
if (!isNumber(width)) {
bbox = group.getBBox();
width = bbox.width;
}
if (!isNumber(height)) {
// get bbox only if it wasn't set before
if (!bbox) {
bbox = group.getBBox();
}
height = bbox.height;
}
// Calculate anchor point
if (!isNumber(anchorX)) {
anchorX = ALIGN_FACTOR.center;
}
if (!isNumber(anchorY)) {
anchorY = ALIGN_FACTOR.center;
}
// Translate group according to its dimension and anchor point
x = x - width * anchorX;
y = y - height * anchorY;
if (chart.animation && defined(group.translateX) && defined(group.translateY)) {
group.animate({
translateX: x,
translateY: y
});
} else {
group.translate(x, y);
}
},
/*
* Destroy the annotation
*/
destroy: function () {
var annotation = this,
chart = this.chart,
allItems = chart.annotations.allItems,
index = allItems.indexOf(annotation);
if (index > -1) {
allItems.splice(index, 1);
}
each(['title', 'shape', 'group'], function (element) {
if (annotation[element]) {
annotation[element].destroy();
annotation[element] = null;
}
});
annotation.group = annotation.title = annotation.shape = annotation.chart = annotation.options = null;
},
/*
* Update the annotation with a given options
*/
update: function (options, redraw) {
extend(this.options, options);
// update link to point or series
this.linkObjects();
this.render(redraw);
},
linkObjects: function () {
var annotation = this,
chart = annotation.chart,
linkedTo = annotation.linkedObject,
linkedId = linkedTo && (linkedTo.id || linkedTo.options.id),
options = annotation.options,
id = options.linkedTo;
if (!defined(id)) {
annotation.linkedObject = null;
} else if (!defined(linkedTo) || id !== linkedId) {
annotation.linkedObject = chart.get(id);
}
}
};
// Add annotations methods to chart prototype
extend(Chart.prototype, {
annotations: {
/*
* Unified method for adding annotations to the chart
*/
add: function (options, redraw) {
var annotations = this.allItems,
chart = this.chart,
item,
len;
if (!isArray(options)) {
options = [options];
}
len = options.length;
while (len--) {
item = new Annotation(chart, options[len]);
annotations.push(item);
item.render(redraw);
}
},
/**
* Redraw all annotations, method used in chart events
*/
redraw: function () {
each(this.allItems, function (annotation) {
annotation.redraw();
});
}
}
});
// Initialize on chart load
Chart.prototype.callbacks.push(function (chart) {
var options = chart.options.annotations,
group;
group = chart.renderer.g("annotations");
group.attr({
zIndex: 7
});
group.add();
// initialize empty array for annotations
chart.annotations.allItems = [];
// link chart object to annotations
chart.annotations.chart = chart;
// link annotations group element to the chart
chart.annotations.group = group;
if (isArray(options) && options.length > 0) {
chart.annotations.add(chart.options.annotations);
}
// update annotations after chart redraw
Highcharts.addEvent(chart, 'redraw', function () {
chart.annotations.redraw();
});
});
}(Highcharts, HighchartsAdapter));
/*
Data plugin for Highcharts
(c) 2012-2013 Torstein Hønsi
Last revision 2013-06-07
License: www.highcharts.com/license
*/
(function(h){var k=h.each,m=function(b,a){this.init(b,a)};h.extend(m.prototype,{init:function(b,a){this.options=b;this.chartOptions=a;this.columns=b.columns||this.rowsToColumns(b.rows)||[];this.columns.length?this.dataFound():(this.parseCSV(),this.parseTable(),this.parseGoogleSpreadsheet())},getColumnDistribution:function(){var b=this.chartOptions,a=b&&b.chart&&b.chart.type,c=[];k(b&&b.series||[],function(b){c.push((h.seriesTypes[b.type||a||"line"].prototype.pointArrayMap||[0]).length)});this.valueCount=
{global:(h.seriesTypes[a||"line"].prototype.pointArrayMap||[0]).length,individual:c}},dataFound:function(){this.parseTypes();this.findHeaderRow();this.parsed();this.complete()},parseCSV:function(){var b=this,a=this.options,c=a.csv,d=this.columns,f=a.startRow||0,i=a.endRow||Number.MAX_VALUE,j=a.startColumn||0,e=a.endColumn||Number.MAX_VALUE,g=0;c&&(c=c.replace(/\r\n/g,"\n").replace(/\r/g,"\n").split(a.lineDelimiter||"\n"),k(c,function(c,h){var n=b.trim(c),p=n.indexOf("#")===0;h>=f&&h<=i&&!p&&n!==""&&
(n=c.split(a.itemDelimiter||","),k(n,function(b,a){a>=j&&a<=e&&(d[a-j]||(d[a-j]=[]),d[a-j][g]=b)}),g+=1)}),this.dataFound())},parseTable:function(){var b=this.options,a=b.table,c=this.columns,d=b.startRow||0,f=b.endRow||Number.MAX_VALUE,i=b.startColumn||0,j=b.endColumn||Number.MAX_VALUE,e;a&&(typeof a==="string"&&(a=document.getElementById(a)),k(a.getElementsByTagName("tr"),function(a,b){e=0;b>=d&&b<=f&&k(a.childNodes,function(a){if((a.tagName==="TD"||a.tagName==="TH")&&e>=i&&e<=j)c[e]||(c[e]=[]),
c[e][b-d]=a.innerHTML,e+=1})}),this.dataFound())},parseGoogleSpreadsheet:function(){var b=this,a=this.options,c=a.googleSpreadsheetKey,d=this.columns,f=a.startRow||0,i=a.endRow||Number.MAX_VALUE,j=a.startColumn||0,e=a.endColumn||Number.MAX_VALUE,g,h;c&&jQuery.getJSON("https://spreadsheets.google.com/feeds/cells/"+c+"/"+(a.googleSpreadsheetWorksheet||"od6")+"/public/values?alt=json-in-script&callback=?",function(a){var a=a.feed.entry,c,k=a.length,m=0,o=0,l;for(l=0;l<k;l++)c=a[l],m=Math.max(m,c.gs$cell.col),
o=Math.max(o,c.gs$cell.row);for(l=0;l<m;l++)if(l>=j&&l<=e)d[l-j]=[],d[l-j].length=Math.min(o,i-f);for(l=0;l<k;l++)if(c=a[l],g=c.gs$cell.row-1,h=c.gs$cell.col-1,h>=j&&h<=e&&g>=f&&g<=i)d[h-j][g-f]=c.content.$t;b.dataFound()})},findHeaderRow:function(){k(this.columns,function(){});this.headerRow=0},trim:function(b){return typeof b==="string"?b.replace(/^\s+|\s+$/g,""):b},parseTypes:function(){for(var b=this.columns,a=b.length,c,d,f,i;a--;)for(c=b[a].length;c--;)d=b[a][c],f=parseFloat(d),i=this.trim(d),
i==f?(b[a][c]=f,f>31536E6?b[a].isDatetime=!0:b[a].isNumeric=!0):(d=this.parseDate(d),a===0&&typeof d==="number"&&!isNaN(d)?(b[a][c]=d,b[a].isDatetime=!0):b[a][c]=i===""?null:i)},dateFormats:{"YYYY-mm-dd":{regex:"^([0-9]{4})-([0-9]{2})-([0-9]{2})$",parser:function(b){return Date.UTC(+b[1],b[2]-1,+b[3])}}},parseDate:function(b){var a=this.options.parseDate,c,d,f;a&&(c=a(b));if(typeof b==="string")for(d in this.dateFormats)a=this.dateFormats[d],(f=b.match(a.regex))&&(c=a.parser(f));return c},rowsToColumns:function(b){var a,
c,d,f,i;if(b){i=[];c=b.length;for(a=0;a<c;a++){f=b[a].length;for(d=0;d<f;d++)i[d]||(i[d]=[]),i[d][a]=b[a][d]}}return i},parsed:function(){this.options.parsed&&this.options.parsed.call(this,this.columns)},complete:function(){var b=this.columns,a,c,d=this.options,f,i,j,e,g,k;if(d.complete){this.getColumnDistribution();b.length>1&&(a=b.shift(),this.headerRow===0&&a.shift(),a.isDatetime?c="datetime":a.isNumeric||(c="category"));for(e=0;e<b.length;e++)if(this.headerRow===0)b[e].name=b[e].shift();i=[];
for(e=0,k=0;e<b.length;k++){f=h.pick(this.valueCount.individual[k],this.valueCount.global);j=[];for(g=0;g<b[e].length;g++)j[g]=[a[g],b[e][g]!==void 0?b[e][g]:null],f>1&&j[g].push(b[e+1][g]!==void 0?b[e+1][g]:null),f>2&&j[g].push(b[e+2][g]!==void 0?b[e+2][g]:null),f>3&&j[g].push(b[e+3][g]!==void 0?b[e+3][g]:null),f>4&&j[g].push(b[e+4][g]!==void 0?b[e+4][g]:null);i[k]={name:b[e].name,data:j};e+=f}d.complete({xAxis:{type:c},series:i})}}});h.Data=m;h.data=function(b,a){return new m(b,a)};h.wrap(h.Chart.prototype,
"init",function(b,a,c){var d=this;a&&a.data?h.data(h.extend(a.data,{complete:function(f){a.series&&k(a.series,function(b,c){a.series[c]=h.merge(b,f.series[c])});a=h.merge(f,a);b.call(d,a,c)}}),a):b.call(d,a,c)})})(Highcharts);
(function(e){function q(b,a,c){return"rgba("+[Math.round(b[0]+(a[0]-b[0])*c),Math.round(b[1]+(a[1]-b[1])*c),Math.round(b[2]+(a[2]-b[2])*c),b[3]+(a[3]-b[3])*c].join(",")+")"}var m=function(){},j=e.getOptions(),g=e.each,n=e.extend,o=e.wrap,h=e.Chart,i=e.seriesTypes,k=i.pie,l=i.column,r=HighchartsAdapter.fireEvent,t=HighchartsAdapter.inArray;n(j.lang,{drillUpText:"◁ Back to {series.name}"});j.drilldown={activeAxisLabelStyle:{cursor:"pointer",color:"#039",fontWeight:"bold",textDecoration:"underline"},
activeDataLabelStyle:{cursor:"pointer",color:"#039",fontWeight:"bold",textDecoration:"underline"},animation:{duration:500},drillUpButton:{position:{align:"right",x:-10,y:10}}};e.SVGRenderer.prototype.Element.prototype.fadeIn=function(){this.attr({opacity:0.1,visibility:"visible"}).animate({opacity:1},{duration:250})};h.prototype.drilldownLevels=[];h.prototype.addSeriesAsDrilldown=function(b,a){var c=b.series,d=c.xAxis,f=c.yAxis,e;e=b.color||c.color;var g,a=n({color:e},a);g=t(b,c.points);this.drilldownLevels.push({seriesOptions:c.userOptions,
shapeArgs:b.shapeArgs,bBox:b.graphic.getBBox(),color:e,newSeries:a,pointOptions:c.options.data[g],pointIndex:g,oldExtremes:{xMin:d&&d.userMin,xMax:d&&d.userMax,yMin:f&&f.userMin,yMax:f&&f.userMax}});e=this.addSeries(a,!1);if(d)d.oldPos=d.pos,d.userMin=d.userMax=null,f.userMin=f.userMax=null;if(c.type===e.type)e.animate=e.animateDrilldown||m,e.options.animation=!0;c.remove(!1);this.redraw();this.showDrillUpButton()};h.prototype.getDrilldownBackText=function(){return this.options.lang.drillUpText.replace("{series.name}",
this.drilldownLevels[this.drilldownLevels.length-1].seriesOptions.name)};h.prototype.showDrillUpButton=function(){var b=this,a=this.getDrilldownBackText(),c=b.options.drilldown.drillUpButton;this.drillUpButton?this.drillUpButton.attr({text:a}).align():this.drillUpButton=this.renderer.button(a,null,null,function(){b.drillUp()}).attr(n({align:c.position.align,zIndex:9},c.theme)).add().align(c.position,!1,c.relativeTo||"plotBox")};h.prototype.drillUp=function(){var b=this.drilldownLevels.pop(),a=this.series[0],
c=b.oldExtremes,d=this.addSeries(b.seriesOptions,!1);r(this,"drillup",{seriesOptions:b.seriesOptions});if(d.type===a.type)d.drilldownLevel=b,d.animate=d.animateDrillupTo||m,d.options.animation=!0,a.animateDrillupFrom&&a.animateDrillupFrom(b);a.remove(!1);d.xAxis&&(d.xAxis.setExtremes(c.xMin,c.xMax,!1),d.yAxis.setExtremes(c.yMin,c.yMax,!1));this.redraw();this.drilldownLevels.length===0?this.drillUpButton=this.drillUpButton.destroy():this.drillUpButton.attr({text:this.getDrilldownBackText()}).align()};
k.prototype.animateDrilldown=function(b){var a=this.chart.drilldownLevels[this.chart.drilldownLevels.length-1],c=this.chart.options.drilldown.animation,d=a.shapeArgs,f=d.start,s=(d.end-f)/this.points.length,h=e.Color(a.color).rgba;b||g(this.points,function(a,b){var g=e.Color(a.color).rgba;a.graphic.attr(e.merge(d,{start:f+b*s,end:f+(b+1)*s})).animate(a.shapeArgs,e.merge(c,{step:function(a,d){d.prop==="start"&&this.attr({fill:q(h,g,d.pos)})}}))})};k.prototype.animateDrillupTo=l.prototype.animateDrillupTo=
function(b){if(!b){var a=this,c=a.drilldownLevel;g(this.points,function(a){a.graphic.hide();a.dataLabel&&a.dataLabel.hide();a.connector&&a.connector.hide()});setTimeout(function(){g(a.points,function(a,b){var e=b===c.pointIndex?"show":"fadeIn";a.graphic[e]();if(a.dataLabel)a.dataLabel[e]();if(a.connector)a.connector[e]()})},Math.max(this.chart.options.drilldown.animation.duration-50,0));this.animate=m}};l.prototype.animateDrilldown=function(b){var a=this.chart.drilldownLevels[this.chart.drilldownLevels.length-
1].shapeArgs,c=this.chart.options.drilldown.animation;b||(a.x+=this.xAxis.oldPos-this.xAxis.pos,g(this.points,function(b){b.graphic.attr(a).animate(b.shapeArgs,c)}))};l.prototype.animateDrillupFrom=k.prototype.animateDrillupFrom=function(b){var a=this.chart.options.drilldown.animation,c=this.group;delete this.group;g(this.points,function(d){var f=d.graphic,g=e.Color(d.color).rgba;delete d.graphic;f.animate(b.shapeArgs,e.merge(a,{step:function(a,c){c.prop==="start"&&this.attr({fill:q(g,e.Color(b.color).rgba,
c.pos)})},complete:function(){f.destroy();c&&(c=c.destroy())}}))})};e.Point.prototype.doDrilldown=function(){for(var b=this.series.chart,a=b.options.drilldown,c=a.series.length,d;c--&&!d;)a.series[c].id===this.drilldown&&(d=a.series[c]);r(b,"drilldown",{point:this,seriesOptions:d});d&&b.addSeriesAsDrilldown(this,d)};o(e.Point.prototype,"init",function(b,a,c,d){var f=b.call(this,a,c,d),b=a.chart,a=(a=a.xAxis&&a.xAxis.ticks[d])&&a.label;if(f.drilldown){if(e.addEvent(f,"click",function(){f.doDrilldown()}),
a){if(!a._basicStyle)a._basicStyle=a.element.getAttribute("style");a.addClass("highcharts-drilldown-axis-label").css(b.options.drilldown.activeAxisLabelStyle).on("click",function(){f.doDrilldown&&f.doDrilldown()})}}else a&&a._basicStyle&&a.element.setAttribute("style",a._basicStyle);return f});o(e.Series.prototype,"drawDataLabels",function(b){var a=this.chart.options.drilldown.activeDataLabelStyle;b.call(this);g(this.points,function(b){if(b.drilldown&&b.dataLabel)b.dataLabel.attr({"class":"highcharts-drilldown-data-label"}).css(a).on("click",
function(){b.doDrilldown()})})});l.prototype.supportsDrilldown=!0;k.prototype.supportsDrilldown=!0;var p,j=function(b){b.call(this);g(this.points,function(a){a.drilldown&&a.graphic&&a.graphic.attr({"class":"highcharts-drilldown-point"}).css({cursor:"pointer"})})};for(p in i)i[p].prototype.supportsDrilldown&&o(i[p].prototype,"drawTracker",j)})(Highcharts);
/*
Highcharts JS v3.0.7 (2013-10-24)
Exporting module
(c) 2010-2013 Torstein Hønsi
License: www.highcharts.com/license
*/
(function(f){var A=f.Chart,t=f.addEvent,C=f.removeEvent,k=f.createElement,n=f.discardElement,u=f.css,o=f.merge,r=f.each,p=f.extend,D=Math.max,j=document,B=window,E=f.isTouchDevice,F=f.Renderer.prototype.symbols,x=f.getOptions(),y;p(x.lang,{printChart:"Print chart",downloadPNG:"Download PNG image",downloadJPEG:"Download JPEG image",downloadPDF:"Download PDF document",downloadSVG:"Download SVG vector image",contextButtonTitle:"Chart context menu"});x.navigation={menuStyle:{border:"1px solid #A0A0A0",
background:"#FFFFFF",padding:"5px 0"},menuItemStyle:{padding:"0 10px",background:"none",color:"#303030",fontSize:E?"14px":"11px"},menuItemHoverStyle:{background:"#4572A5",color:"#FFFFFF"},buttonOptions:{symbolFill:"#E0E0E0",symbolSize:14,symbolStroke:"#666",symbolStrokeWidth:3,symbolX:12.5,symbolY:10.5,align:"right",buttonSpacing:3,height:22,theme:{fill:"white",stroke:"none"},verticalAlign:"top",width:24}};x.exporting={type:"image/png",url:"http://export.highcharts.com/",buttons:{contextButton:{menuClassName:"highcharts-contextmenu",
symbol:"menu",_titleKey:"contextButtonTitle",menuItems:[{textKey:"printChart",onclick:function(){this.print()}},{separator:!0},{textKey:"downloadPNG",onclick:function(){this.exportChart()}},{textKey:"downloadJPEG",onclick:function(){this.exportChart({type:"image/jpeg"})}},{textKey:"downloadPDF",onclick:function(){this.exportChart({type:"application/pdf"})}},{textKey:"downloadSVG",onclick:function(){this.exportChart({type:"image/svg+xml"})}}]}}};f.post=function(c,a){var d,b;b=k("form",{method:"post",
action:c,enctype:"multipart/form-data"},{display:"none"},j.body);for(d in a)k("input",{type:"hidden",name:d,value:a[d]},null,b);b.submit();n(b)};p(A.prototype,{getSVG:function(c){var a=this,d,b,z,h,g=o(a.options,c);if(!j.createElementNS)j.createElementNS=function(a,b){return j.createElement(b)};c=k("div",null,{position:"absolute",top:"-9999em",width:a.chartWidth+"px",height:a.chartHeight+"px"},j.body);b=a.renderTo.style.width;h=a.renderTo.style.height;b=g.exporting.sourceWidth||g.chart.width||/px$/.test(b)&&
parseInt(b,10)||600;h=g.exporting.sourceHeight||g.chart.height||/px$/.test(h)&&parseInt(h,10)||400;p(g.chart,{animation:!1,renderTo:c,forExport:!0,width:b,height:h});g.exporting.enabled=!1;g.series=[];r(a.series,function(a){z=o(a.options,{animation:!1,showCheckbox:!1,visible:a.visible});z.isInternal||g.series.push(z)});d=new f.Chart(g,a.callback);r(["xAxis","yAxis"],function(b){r(a[b],function(a,c){var g=d[b][c],f=a.getExtremes(),h=f.userMin,f=f.userMax;g&&(h!==void 0||f!==void 0)&&g.setExtremes(h,
f,!0,!1)})});b=d.container.innerHTML;g=null;d.destroy();n(c);b=b.replace(/zIndex="[^"]+"/g,"").replace(/isShadow="[^"]+"/g,"").replace(/symbolName="[^"]+"/g,"").replace(/jQuery[0-9]+="[^"]+"/g,"").replace(/url\([^#]+#/g,"url(#").replace(/<svg /,'<svg xmlns:xlink="http://www.w3.org/1999/xlink" ').replace(/ href=/g," xlink:href=").replace(/\n/," ").replace(/<\/svg>.*?$/,"</svg>").replace(/&nbsp;/g," ").replace(/&shy;/g,"­").replace(/<IMG /g,"<image ").replace(/height=([^" ]+)/g,'height="$1"').replace(/width=([^" ]+)/g,
'width="$1"').replace(/hc-svg-href="([^"]+)">/g,'xlink:href="$1"/>').replace(/id=([^" >]+)/g,'id="$1"').replace(/class=([^" >]+)/g,'class="$1"').replace(/ transform /g," ").replace(/:(path|rect)/g,"$1").replace(/style="([^"]+)"/g,function(a){return a.toLowerCase()});return b=b.replace(/(url\(#highcharts-[0-9]+)&quot;/g,"$1").replace(/&quot;/g,"'")},exportChart:function(c,a){var c=c||{},d=this.options.exporting,d=this.getSVG(o({chart:{borderRadius:0}},d.chartOptions,a,{exporting:{sourceWidth:c.sourceWidth||
d.sourceWidth,sourceHeight:c.sourceHeight||d.sourceHeight}})),c=o(this.options.exporting,c);f.post(c.url,{filename:c.filename||"chart",type:c.type,width:c.width||0,scale:c.scale||2,svg:d})},print:function(){var c=this,a=c.container,d=[],b=a.parentNode,f=j.body,h=f.childNodes;if(!c.isPrinting)c.isPrinting=!0,r(h,function(a,b){if(a.nodeType===1)d[b]=a.style.display,a.style.display="none"}),f.appendChild(a),B.focus(),B.print(),setTimeout(function(){b.appendChild(a);r(h,function(a,b){if(a.nodeType===
1)a.style.display=d[b]});c.isPrinting=!1},1E3)},contextMenu:function(c,a,d,b,f,h,g){var e=this,j=e.options.navigation,q=j.menuItemStyle,l=e.chartWidth,m=e.chartHeight,o="cache-"+c,i=e[o],s=D(f,h),v,w,n;if(!i)e[o]=i=k("div",{className:c},{position:"absolute",zIndex:1E3,padding:s+"px"},e.container),v=k("div",null,p({MozBoxShadow:"3px 3px 10px #888",WebkitBoxShadow:"3px 3px 10px #888",boxShadow:"3px 3px 10px #888"},j.menuStyle),i),w=function(){u(i,{display:"none"});g&&g.setState(0);e.openMenu=!1},t(i,
"mouseleave",function(){n=setTimeout(w,500)}),t(i,"mouseenter",function(){clearTimeout(n)}),t(document,"mouseup",function(a){e.pointer.inClass(a.target,c)||w()}),r(a,function(a){if(a){var b=a.separator?k("hr",null,null,v):k("div",{onmouseover:function(){u(this,j.menuItemHoverStyle)},onmouseout:function(){u(this,q)},onclick:function(){w();a.onclick.apply(e,arguments)},innerHTML:a.text||e.options.lang[a.textKey]},p({cursor:"pointer"},q),v);e.exportDivElements.push(b)}}),e.exportDivElements.push(v,i),
e.exportMenuWidth=i.offsetWidth,e.exportMenuHeight=i.offsetHeight;a={display:"block"};d+e.exportMenuWidth>l?a.right=l-d-f-s+"px":a.left=d-s+"px";b+h+e.exportMenuHeight>m&&g.alignOptions.verticalAlign!=="top"?a.bottom=m-b-s+"px":a.top=b+h-s+"px";u(i,a);e.openMenu=!0},addButton:function(c){var a=this,d=a.renderer,b=o(a.options.navigation.buttonOptions,c),j=b.onclick,h=b.menuItems,g,e,k={stroke:b.symbolStroke,fill:b.symbolFill},q=b.symbolSize||12;if(!a.btnCount)a.btnCount=0;if(!a.exportDivElements)a.exportDivElements=
[],a.exportSVGElements=[];if(b.enabled!==!1){var l=b.theme,m=l.states,n=m&&m.hover,m=m&&m.select,i;delete l.states;j?i=function(){j.apply(a,arguments)}:h&&(i=function(){a.contextMenu(e.menuClassName,h,e.translateX,e.translateY,e.width,e.height,e);e.setState(2)});b.text&&b.symbol?l.paddingLeft=f.pick(l.paddingLeft,25):b.text||p(l,{width:b.width,height:b.height,padding:0});e=d.button(b.text,0,0,i,l,n,m).attr({title:a.options.lang[b._titleKey],"stroke-linecap":"round"});e.menuClassName=c.menuClassName||
"highcharts-menu-"+a.btnCount++;b.symbol&&(g=d.symbol(b.symbol,b.symbolX-q/2,b.symbolY-q/2,q,q).attr(p(k,{"stroke-width":b.symbolStrokeWidth||1,zIndex:1})).add(e));e.add().align(p(b,{width:e.width,x:f.pick(b.x,y)}),!0,"spacingBox");y+=(e.width+b.buttonSpacing)*(b.align==="right"?-1:1);a.exportSVGElements.push(e,g)}},destroyExport:function(c){var c=c.target,a,d;for(a=0;a<c.exportSVGElements.length;a++)if(d=c.exportSVGElements[a])d.onclick=d.ontouchstart=null,c.exportSVGElements[a]=d.destroy();for(a=
0;a<c.exportDivElements.length;a++)d=c.exportDivElements[a],C(d,"mouseleave"),c.exportDivElements[a]=d.onmouseout=d.onmouseover=d.ontouchstart=d.onclick=null,n(d)}});F.menu=function(c,a,d,b){return["M",c,a+2.5,"L",c+d,a+2.5,"M",c,a+b/2+0.5,"L",c+d,a+b/2+0.5,"M",c,a+b-1.5,"L",c+d,a+b-1.5]};A.prototype.callbacks.push(function(c){var a,d=c.options.exporting,b=d.buttons;y=0;if(d.enabled!==!1){for(a in b)c.addButton(b[a]);t(c,"destroy",c.destroyExport)}})})(Highcharts);
/*
Highcharts funnel module, Beta
(c) 2010-2012 Torstein Hønsi
License: www.highcharts.com/license
*/
(function(d){var u=d.getOptions().plotOptions,p=d.seriesTypes,D=d.merge,z=function(){},A=d.each;u.funnel=D(u.pie,{center:["50%","50%"],width:"90%",neckWidth:"30%",height:"100%",neckHeight:"25%",dataLabels:{connectorWidth:1,connectorColor:"#606060"},size:!0,states:{select:{color:"#C0C0C0",borderColor:"#000000",shadow:!1}}});p.funnel=d.extendClass(p.pie,{type:"funnel",animate:z,translate:function(){var a=function(k,a){return/%$/.test(k)?a*parseInt(k,10)/100:parseInt(k,10)},g=0,e=this.chart,f=e.plotWidth,
e=e.plotHeight,h=0,c=this.options,C=c.center,b=a(C[0],f),d=a(C[0],e),p=a(c.width,f),i,q,j=a(c.height,e),r=a(c.neckWidth,f),s=a(c.neckHeight,e),v=j-s,a=this.data,w,x,u=c.dataLabels.position==="left"?1:0,y,m,B,n,l,t,o;this.getWidthAt=q=function(k){return k>j-s||j===s?r:r+(p-r)*((j-s-k)/(j-s))};this.getX=function(k,a){return b+(a?-1:1)*(q(k)/2+c.dataLabels.distance)};this.center=[b,d,j];this.centerX=b;A(a,function(a){g+=a.y});A(a,function(a){o=null;x=g?a.y/g:0;m=d-j/2+h*j;l=m+x*j;i=q(m);y=b-i/2;B=y+
i;i=q(l);n=b-i/2;t=n+i;m>v?(y=n=b-r/2,B=t=b+r/2):l>v&&(o=l,i=q(v),n=b-i/2,t=n+i,l=v);w=["M",y,m,"L",B,m,t,l];o&&w.push(t,o,n,o);w.push(n,l,"Z");a.shapeType="path";a.shapeArgs={d:w};a.percentage=x*100;a.plotX=b;a.plotY=(m+(o||l))/2;a.tooltipPos=[b,a.plotY];a.slice=z;a.half=u;h+=x});this.setTooltipPoints()},drawPoints:function(){var a=this,g=a.options,e=a.chart.renderer;A(a.data,function(f){var h=f.graphic,c=f.shapeArgs;h?h.animate(c):f.graphic=e.path(c).attr({fill:f.color,stroke:g.borderColor,"stroke-width":g.borderWidth}).add(a.group)})},
sortByAngle:z,drawDataLabels:function(){var a=this.data,g=this.options.dataLabels.distance,e,f,h,c=a.length,d,b;for(this.center[2]-=2*g;c--;)h=a[c],f=(e=h.half)?1:-1,b=h.plotY,d=this.getX(b,e),h.labelPos=[0,b,d+(g-5)*f,b,d+g*f,b,e?"right":"left",0];p.pie.prototype.drawDataLabels.call(this)}})})(Highcharts);
/**
* @license
* Highcharts funnel module, Beta
*
* (c) 2010-2012 Torstein Hønsi
*
* License: www.highcharts.com/license
*/
/*global Highcharts */
(function (Highcharts) {
'use strict';
// create shortcuts
var defaultOptions = Highcharts.getOptions(),
defaultPlotOptions = defaultOptions.plotOptions,
seriesTypes = Highcharts.seriesTypes,
merge = Highcharts.merge,
noop = function () {},
each = Highcharts.each;
// set default options
defaultPlotOptions.funnel = merge(defaultPlotOptions.pie, {
center: ['50%', '50%'],
width: '90%',
neckWidth: '30%',
height: '100%',
neckHeight: '25%',
dataLabels: {
//position: 'right',
connectorWidth: 1,
connectorColor: '#606060'
},
size: true, // to avoid adapting to data label size in Pie.drawDataLabels
states: {
select: {
color: '#C0C0C0',
borderColor: '#000000',
shadow: false
}
}
});
seriesTypes.funnel = Highcharts.extendClass(seriesTypes.pie, {
type: 'funnel',
animate: noop,
/**
* Overrides the pie translate method
*/
translate: function () {
var
// Get positions - either an integer or a percentage string must be given
getLength = function (length, relativeTo) {
return (/%$/).test(length) ?
relativeTo * parseInt(length, 10) / 100 :
parseInt(length, 10);
},
sum = 0,
series = this,
chart = series.chart,
plotWidth = chart.plotWidth,
plotHeight = chart.plotHeight,
cumulative = 0, // start at top
options = series.options,
center = options.center,
centerX = getLength(center[0], plotWidth),
centerY = getLength(center[0], plotHeight),
width = getLength(options.width, plotWidth),
tempWidth,
getWidthAt,
height = getLength(options.height, plotHeight),
neckWidth = getLength(options.neckWidth, plotWidth),
neckHeight = getLength(options.neckHeight, plotHeight),
neckY = height - neckHeight,
data = series.data,
path,
fraction,
half = options.dataLabels.position === 'left' ? 1 : 0,
x1,
y1,
x2,
x3,
y3,
x4,
y5;
// Return the width at a specific y coordinate
series.getWidthAt = getWidthAt = function (y) {
return y > height - neckHeight || height === neckHeight ?
neckWidth :
neckWidth + (width - neckWidth) * ((height - neckHeight - y) / (height - neckHeight));
};
series.getX = function (y, half) {
return centerX + (half ? -1 : 1) * ((getWidthAt(y) / 2) + options.dataLabels.distance);
};
// Expose
series.center = [centerX, centerY, height];
series.centerX = centerX;
/*
* Individual point coordinate naming:
*
* x1,y1 _________________ x2,y1
* \ /
* \ /
* \ /
* \ /
* \ /
* x3,y3 _________ x4,y3
*
* Additional for the base of the neck:
*
* | |
* | |
* | |
* x3,y5 _________ x4,y5
*/
// get the total sum
each(data, function (point) {
sum += point.y;
});
each(data, function (point) {
// set start and end positions
y5 = null;
fraction = sum ? point.y / sum : 0;
y1 = centerY - height / 2 + cumulative * height;
y3 = y1 + fraction * height;
//tempWidth = neckWidth + (width - neckWidth) * ((height - neckHeight - y1) / (height - neckHeight));
tempWidth = getWidthAt(y1);
x1 = centerX - tempWidth / 2;
x2 = x1 + tempWidth;
tempWidth = getWidthAt(y3);
x3 = centerX - tempWidth / 2;
x4 = x3 + tempWidth;
// the entire point is within the neck
if (y1 > neckY) {
x1 = x3 = centerX - neckWidth / 2;
x2 = x4 = centerX + neckWidth / 2;
// the base of the neck
} else if (y3 > neckY) {
y5 = y3;
tempWidth = getWidthAt(neckY);
x3 = centerX - tempWidth / 2;
x4 = x3 + tempWidth;
y3 = neckY;
}
// save the path
path = [
'M',
x1, y1,
'L',
x2, y1,
x4, y3
];
if (y5) {
path.push(x4, y5, x3, y5);
}
path.push(x3, y3, 'Z');
// prepare for using shared dr
point.shapeType = 'path';
point.shapeArgs = { d: path };
// for tooltips and data labels
point.percentage = fraction * 100;
point.plotX = centerX;
point.plotY = (y1 + (y5 || y3)) / 2;
// Placement of tooltips and data labels
point.tooltipPos = [
centerX,
point.plotY
];
// Slice is a noop on funnel points
point.slice = noop;
// Mimicking pie data label placement logic
point.half = half;
cumulative += fraction;
});
series.setTooltipPoints();
},
/**
* Draw a single point (wedge)
* @param {Object} point The point object
* @param {Object} color The color of the point
* @param {Number} brightness The brightness relative to the color
*/
drawPoints: function () {
var series = this,
options = series.options,
chart = series.chart,
renderer = chart.renderer;
each(series.data, function (point) {
var graphic = point.graphic,
shapeArgs = point.shapeArgs;
if (!graphic) { // Create the shapes
point.graphic = renderer.path(shapeArgs).
attr({
fill: point.color,
stroke: options.borderColor,
'stroke-width': options.borderWidth
}).
add(series.group);
} else { // Update the shapes
graphic.animate(shapeArgs);
}
});
},
/**
* Funnel items don't have angles (#2289)
*/
sortByAngle: noop,
/**
* Extend the pie data label method
*/
drawDataLabels: function () {
var data = this.data,
labelDistance = this.options.dataLabels.distance,
leftSide,
sign,
point,
i = data.length,
x,
y;
// In the original pie label anticollision logic, the slots are distributed
// from one labelDistance above to one labelDistance below the pie. In funnels
// we don't want this.
this.center[2] -= 2 * labelDistance;
// Set the label position array for each point.
while (i--) {
point = data[i];
leftSide = point.half;
sign = leftSide ? 1 : -1;
y = point.plotY;
x = this.getX(y, leftSide);
// set the anchor point for data labels
point.labelPos = [
0, // first break of connector
y, // a/a
x + (labelDistance - 5) * sign, // second break, right outside point shape
y, // a/a
x + labelDistance * sign, // landing point for connector
y, // a/a
leftSide ? 'right' : 'left', // alignment
0 // center angle
];
}
seriesTypes.pie.prototype.drawDataLabels.call(this);
}
});
}(Highcharts));
(function(a){var k=a.seriesTypes,l=a.each;k.heatmap=a.extendClass(k.map,{colorKey:"z",useMapGeometry:!1,pointArrayMap:["y","z"],translate:function(){var c=this,a=c.options,i=Number.MAX_VALUE,j=Number.MIN_VALUE;c.generatePoints();l(c.data,function(b){var e=b.x,f=b.y,d=b.z,g=(a.colsize||1)/2,h=(a.rowsize||1)/2;b.path=["M",e-g,f-h,"L",e+g,f-h,"L",e+g,f+h,"L",e-g,f+h,"Z"];b.shapeType="path";b.shapeArgs={d:c.translatePath(b.path)};typeof d==="number"&&(d>j?j=d:d<i&&(i=d))});c.translateColors(i,j)},getBox:function(){},
getExtremes:a.Series.prototype.getExtremes})})(Highcharts);
(function (H) {
var seriesTypes = H.seriesTypes,
each = H.each;
seriesTypes.heatmap = H.extendClass(seriesTypes.map, {
colorKey: 'z',
useMapGeometry: false,
pointArrayMap: ['y', 'z'],
translate: function () {
var series = this,
options = series.options,
dataMin = Number.MAX_VALUE,
dataMax = Number.MIN_VALUE;
series.generatePoints();
each(series.data, function (point) {
var x = point.x,
y = point.y,
value = point.z,
xPad = (options.colsize || 1) / 2,
yPad = (options.rowsize || 1) / 2;
point.path = [
'M', x - xPad, y - yPad,
'L', x + xPad, y - yPad,
'L', x + xPad, y + yPad,
'L', x - xPad, y + yPad,
'Z'
];
point.shapeType = 'path';
point.shapeArgs = {
d: series.translatePath(point.path)
};
if (typeof value === 'number') {
if (value > dataMax) {
dataMax = value;
} else if (value < dataMin) {
dataMin = value;
}
}
});
series.translateColors(dataMin, dataMax);
},
getBox: function () {},
getExtremes: H.Series.prototype.getExtremes
});
}(Highcharts));
/*
Highcharts JS v3.0.7 (2013-10-24)
Plugin for displaying a message when there is no data visible in chart.
(c) 2010-2013 Highsoft AS
Author: Øystein Moseng
License: www.highcharts.com/license
*/
(function(c){function f(){return!!this.points.length}function g(){this.hasData()?this.hideNoData():this.showNoData()}var d=c.seriesTypes,e=c.Chart.prototype,h=c.getOptions(),i=c.extend;i(h.lang,{noData:"No data to display"});h.noData={position:{x:0,y:0,align:"center",verticalAlign:"middle"},attr:{},style:{fontWeight:"bold",fontSize:"12px",color:"#60606a"}};d.pie.prototype.hasData=f;if(d.gauge)d.gauge.prototype.hasData=f;if(d.waterfall)d.waterfall.prototype.hasData=f;c.Series.prototype.hasData=function(){return this.dataMax!==
void 0&&this.dataMin!==void 0};e.showNoData=function(a){var b=this.options,a=a||b.lang.noData,b=b.noData;if(!this.noDataLabel)this.noDataLabel=this.renderer.label(a,0,0,null,null,null,null,null,"no-data").attr(b.attr).css(b.style).add(),this.noDataLabel.align(i(this.noDataLabel.getBBox(),b.position),!1,"plotBox")};e.hideNoData=function(){if(this.noDataLabel)this.noDataLabel=this.noDataLabel.destroy()};e.hasData=function(){for(var a=this.series,b=a.length;b--;)if(a[b].hasData()&&!a[b].options.isInternal)return!0;
return!1};e.callbacks.push(function(a){c.addEvent(a,"load",g);c.addEvent(a,"redraw",g)})})(Highcharts);
/**
* @license Highcharts JS v3.0.7 (2013-10-24)
* Plugin for displaying a message when there is no data visible in chart.
*
* (c) 2010-2013 Highsoft AS
* Author: Øystein Moseng
*
* License: www.highcharts.com/license
*/
(function (H) { // docs
var seriesTypes = H.seriesTypes,
chartPrototype = H.Chart.prototype,
defaultOptions = H.getOptions(),
extend = H.extend;
// Add language option
extend(defaultOptions.lang, {
noData: 'No data to display'
});
// Add default display options for message
defaultOptions.noData = {
position: {
x: 0,
y: 0,
align: 'center',
verticalAlign: 'middle'
},
attr: {
},
style: {
fontWeight: 'bold',
fontSize: '12px',
color: '#60606a'
}
};
/**
* Define hasData functions for series. These return true if there are data points on this series within the plot area
*/
function hasDataPie() {
return !!this.points.length; /* != 0 */
}
seriesTypes.pie.prototype.hasData = hasDataPie;
if (seriesTypes.gauge) {
seriesTypes.gauge.prototype.hasData = hasDataPie;
}
if (seriesTypes.waterfall) {
seriesTypes.waterfall.prototype.hasData = hasDataPie;
}
H.Series.prototype.hasData = function () {
return this.dataMax !== undefined && this.dataMin !== undefined;
};
/**
* Display a no-data message.
*
* @param {String} str An optional message to show in place of the default one
*/
chartPrototype.showNoData = function (str) {
var chart = this,
options = chart.options,
text = str || options.lang.noData,
noDataOptions = options.noData;
if (!chart.noDataLabel) {
chart.noDataLabel = chart.renderer.label(text, 0, 0, null, null, null, null, null, 'no-data')
.attr(noDataOptions.attr)
.css(noDataOptions.style)
.add();
chart.noDataLabel.align(extend(chart.noDataLabel.getBBox(), noDataOptions.position), false, 'plotBox');
}
};
/**
* Hide no-data message
*/
chartPrototype.hideNoData = function () {
var chart = this;
if (chart.noDataLabel) {
chart.noDataLabel = chart.noDataLabel.destroy();
}
};
/**
* Returns true if there are data points within the plot area now
*/
chartPrototype.hasData = function () {
var chart = this,
series = chart.series,
i = series.length;
while (i--) {
if (series[i].hasData() && !series[i].options.isInternal) {
return true;
}
}
return false;
};
/**
* Show no-data message if there is no data in sight. Otherwise, hide it.
*/
function handleNoData() {
var chart = this;
if (chart.hasData()) {
chart.hideNoData();
} else {
chart.showNoData();
}
}
/**
* Add event listener to handle automatic display of no-data message
*/
chartPrototype.callbacks.push(function (chart) {
H.addEvent(chart, 'load', handleNoData);
H.addEvent(chart, 'redraw', handleNoData);
});
}(Highcharts));
/**
* Dark blue theme for Highcharts JS
* @author Torstein Hønsi
*/
Highcharts.theme = {
colors: ["#DDDF0D", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee",
"#55BF3B", "#DF5353", "#7798BF", "#aaeeee"],
chart: {
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 },
stops: [
[0, 'rgb(48, 48, 96)'],
[1, 'rgb(0, 0, 0)']
]
},
borderColor: '#000000',
borderWidth: 2,
className: 'dark-container',
plotBackgroundColor: 'rgba(255, 255, 255, .1)',
plotBorderColor: '#CCCCCC',
plotBorderWidth: 1
},
title: {
style: {
color: '#C0C0C0',
font: 'bold 16px "Trebuchet MS", Verdana, sans-serif'
}
},
subtitle: {
style: {
color: '#666666',
font: 'bold 12px "Trebuchet MS", Verdana, sans-serif'
}
},
xAxis: {
gridLineColor: '#333333',
gridLineWidth: 1,
labels: {
style: {
color: '#A0A0A0'
}
},
lineColor: '#A0A0A0',
tickColor: '#A0A0A0',
title: {
style: {
color: '#CCC',
fontWeight: 'bold',
fontSize: '12px',
fontFamily: 'Trebuchet MS, Verdana, sans-serif'
}
}
},
yAxis: {
gridLineColor: '#333333',
labels: {
style: {
color: '#A0A0A0'
}
},
lineColor: '#A0A0A0',
minorTickInterval: null,
tickColor: '#A0A0A0',
tickWidth: 1,
title: {
style: {
color: '#CCC',
fontWeight: 'bold',
fontSize: '12px',
fontFamily: 'Trebuchet MS, Verdana, sans-serif'
}
}
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0.75)',
style: {
color: '#F0F0F0'
}
},
toolbar: {
itemStyle: {
color: 'silver'
}
},
plotOptions: {
line: {
dataLabels: {
color: '#CCC'
},
marker: {
lineColor: '#333'
}
},
spline: {
marker: {
lineColor: '#333'
}
},
scatter: {
marker: {
lineColor: '#333'
}
},
candlestick: {
lineColor: 'white'
}
},
legend: {
itemStyle: {
font: '9pt Trebuchet MS, Verdana, sans-serif',
color: '#A0A0A0'
},
itemHoverStyle: {
color: '#FFF'
},
itemHiddenStyle: {
color: '#444'
}
},
credits: {
style: {
color: '#666'
}
},
labels: {
style: {
color: '#CCC'
}
},
navigation: {
buttonOptions: {
symbolStroke: '#DDDDDD',
hoverSymbolStroke: '#FFFFFF',
theme: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#606060'],
[0.6, '#333333']
]
},
stroke: '#000000'
}
}
},
// scroll charts
rangeSelector: {
buttonTheme: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
stroke: '#000000',
style: {
color: '#CCC',
fontWeight: 'bold'
},
states: {
hover: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#BBB'],
[0.6, '#888']
]
},
stroke: '#000000',
style: {
color: 'white'
}
},
select: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.1, '#000'],
[0.3, '#333']
]
},
stroke: '#000000',
style: {
color: 'yellow'
}
}
}
},
inputStyle: {
backgroundColor: '#333',
color: 'silver'
},
labelStyle: {
color: 'silver'
}
},
navigator: {
handles: {
backgroundColor: '#666',
borderColor: '#AAA'
},
outlineColor: '#CCC',
maskFill: 'rgba(16, 16, 16, 0.5)',
series: {
color: '#7798BF',
lineColor: '#A6C7ED'
}
},
scrollbar: {
barBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
barBorderColor: '#CCC',
buttonArrowColor: '#CCC',
buttonBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
buttonBorderColor: '#CCC',
rifleColor: '#FFF',
trackBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, '#000'],
[1, '#333']
]
},
trackBorderColor: '#666'
},
// special colors for some of the
legendBackgroundColor: 'rgba(0, 0, 0, 0.5)',
legendBackgroundColorSolid: 'rgb(35, 35, 70)',
dataLabelsColor: '#444',
textColor: '#C0C0C0',
maskColor: 'rgba(255,255,255,0.3)'
};
// Apply the theme
var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
/**
* Dark blue theme for Highcharts JS
* @author Torstein Hønsi
*/
Highcharts.theme = {
colors: ["#DDDF0D", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee",
"#55BF3B", "#DF5353", "#7798BF", "#aaeeee"],
chart: {
backgroundColor: {
linearGradient: [0, 0, 250, 500],
stops: [
[0, 'rgb(48, 96, 48)'],
[1, 'rgb(0, 0, 0)']
]
},
borderColor: '#000000',
borderWidth: 2,
className: 'dark-container',
plotBackgroundColor: 'rgba(255, 255, 255, .1)',
plotBorderColor: '#CCCCCC',
plotBorderWidth: 1
},
title: {
style: {
color: '#C0C0C0',
font: 'bold 16px "Trebuchet MS", Verdana, sans-serif'
}
},
subtitle: {
style: {
color: '#666666',
font: 'bold 12px "Trebuchet MS", Verdana, sans-serif'
}
},
xAxis: {
gridLineColor: '#333333',
gridLineWidth: 1,
labels: {
style: {
color: '#A0A0A0'
}
},
lineColor: '#A0A0A0',
tickColor: '#A0A0A0',
title: {
style: {
color: '#CCC',
fontWeight: 'bold',
fontSize: '12px',
fontFamily: 'Trebuchet MS, Verdana, sans-serif'
}
}
},
yAxis: {
gridLineColor: '#333333',
labels: {
style: {
color: '#A0A0A0'
}
},
lineColor: '#A0A0A0',
minorTickInterval: null,
tickColor: '#A0A0A0',
tickWidth: 1,
title: {
style: {
color: '#CCC',
fontWeight: 'bold',
fontSize: '12px',
fontFamily: 'Trebuchet MS, Verdana, sans-serif'
}
}
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0.75)',
style: {
color: '#F0F0F0'
}
},
toolbar: {
itemStyle: {
color: 'silver'
}
},
plotOptions: {
line: {
dataLabels: {
color: '#CCC'
},
marker: {
lineColor: '#333'
}
},
spline: {
marker: {
lineColor: '#333'
}
},
scatter: {
marker: {
lineColor: '#333'
}
},
candlestick: {
lineColor: 'white'
}
},
legend: {
itemStyle: {
font: '9pt Trebuchet MS, Verdana, sans-serif',
color: '#A0A0A0'
},
itemHoverStyle: {
color: '#FFF'
},
itemHiddenStyle: {
color: '#444'
}
},
credits: {
style: {
color: '#666'
}
},
labels: {
style: {
color: '#CCC'
}
},
navigation: {
buttonOptions: {
symbolStroke: '#DDDDDD',
hoverSymbolStroke: '#FFFFFF',
theme: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#606060'],
[0.6, '#333333']
]
},
stroke: '#000000'
}
}
},
// scroll charts
rangeSelector: {
buttonTheme: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
stroke: '#000000',
style: {
color: '#CCC',
fontWeight: 'bold'
},
states: {
hover: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#BBB'],
[0.6, '#888']
]
},
stroke: '#000000',
style: {
color: 'white'
}
},
select: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.1, '#000'],
[0.3, '#333']
]
},
stroke: '#000000',
style: {
color: 'yellow'
}
}
}
},
inputStyle: {
backgroundColor: '#333',
color: 'silver'
},
labelStyle: {
color: 'silver'
}
},
navigator: {
handles: {
backgroundColor: '#666',
borderColor: '#AAA'
},
outlineColor: '#CCC',
maskFill: 'rgba(16, 16, 16, 0.5)',
series: {
color: '#7798BF',
lineColor: '#A6C7ED'
}
},
scrollbar: {
barBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
barBorderColor: '#CCC',
buttonArrowColor: '#CCC',
buttonBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
buttonBorderColor: '#CCC',
rifleColor: '#FFF',
trackBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, '#000'],
[1, '#333']
]
},
trackBorderColor: '#666'
},
// special colors for some of the
legendBackgroundColor: 'rgba(0, 0, 0, 0.5)',
legendBackgroundColorSolid: 'rgb(35, 35, 70)',
dataLabelsColor: '#444',
textColor: '#C0C0C0',
maskColor: 'rgba(255,255,255,0.3)'
};
// Apply the theme
var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
/**
* Gray theme for Highcharts JS
* @author Torstein Hønsi
*/
Highcharts.theme = {
colors: ["#DDDF0D", "#7798BF", "#55BF3B", "#DF5353", "#aaeeee", "#ff0066", "#eeaaee",
"#55BF3B", "#DF5353", "#7798BF", "#aaeeee"],
chart: {
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, 'rgb(96, 96, 96)'],
[1, 'rgb(16, 16, 16)']
]
},
borderWidth: 0,
borderRadius: 15,
plotBackgroundColor: null,
plotShadow: false,
plotBorderWidth: 0
},
title: {
style: {
color: '#FFF',
font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
}
},
subtitle: {
style: {
color: '#DDD',
font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
}
},
xAxis: {
gridLineWidth: 0,
lineColor: '#999',
tickColor: '#999',
labels: {
style: {
color: '#999',
fontWeight: 'bold'
}
},
title: {
style: {
color: '#AAA',
font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
}
}
},
yAxis: {
alternateGridColor: null,
minorTickInterval: null,
gridLineColor: 'rgba(255, 255, 255, .1)',
minorGridLineColor: 'rgba(255,255,255,0.07)',
lineWidth: 0,
tickWidth: 0,
labels: {
style: {
color: '#999',
fontWeight: 'bold'
}
},
title: {
style: {
color: '#AAA',
font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
}
}
},
legend: {
itemStyle: {
color: '#CCC'
},
itemHoverStyle: {
color: '#FFF'
},
itemHiddenStyle: {
color: '#333'
}
},
labels: {
style: {
color: '#CCC'
}
},
tooltip: {
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, 'rgba(96, 96, 96, .8)'],
[1, 'rgba(16, 16, 16, .8)']
]
},
borderWidth: 0,
style: {
color: '#FFF'
}
},
plotOptions: {
series: {
shadow: true
},
line: {
dataLabels: {
color: '#CCC'
},
marker: {
lineColor: '#333'
}
},
spline: {
marker: {
lineColor: '#333'
}
},
scatter: {
marker: {
lineColor: '#333'
}
},
candlestick: {
lineColor: 'white'
}
},
toolbar: {
itemStyle: {
color: '#CCC'
}
},
navigation: {
buttonOptions: {
symbolStroke: '#DDDDDD',
hoverSymbolStroke: '#FFFFFF',
theme: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#606060'],
[0.6, '#333333']
]
},
stroke: '#000000'
}
}
},
// scroll charts
rangeSelector: {
buttonTheme: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
stroke: '#000000',
style: {
color: '#CCC',
fontWeight: 'bold'
},
states: {
hover: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#BBB'],
[0.6, '#888']
]
},
stroke: '#000000',
style: {
color: 'white'
}
},
select: {
fill: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.1, '#000'],
[0.3, '#333']
]
},
stroke: '#000000',
style: {
color: 'yellow'
}
}
}
},
inputStyle: {
backgroundColor: '#333',
color: 'silver'
},
labelStyle: {
color: 'silver'
}
},
navigator: {
handles: {
backgroundColor: '#666',
borderColor: '#AAA'
},
outlineColor: '#CCC',
maskFill: 'rgba(16, 16, 16, 0.5)',
series: {
color: '#7798BF',
lineColor: '#A6C7ED'
}
},
scrollbar: {
barBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
barBorderColor: '#CCC',
buttonArrowColor: '#CCC',
buttonBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0.4, '#888'],
[0.6, '#555']
]
},
buttonBorderColor: '#CCC',
rifleColor: '#FFF',
trackBackgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [
[0, '#000'],
[1, '#333']
]
},
trackBorderColor: '#666'
},
// special colors for some of the demo examples
legendBackgroundColor: 'rgba(48, 48, 48, 0.8)',
legendBackgroundColorSolid: 'rgb(70, 70, 70)',
dataLabelsColor: '#444',
textColor: '#E0E0E0',
maskColor: 'rgba(255,255,255,0.3)'
};
// Apply the theme
var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
/**
* Grid theme for Highcharts JS
* @author Torstein Hønsi
*/
Highcharts.theme = {
colors: ['#058DC7', '#50B432', '#ED561B', '#DDDF00', '#24CBE5', '#64E572', '#FF9655', '#FFF263', '#6AF9C4'],
chart: {
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 },
stops: [
[0, 'rgb(255, 255, 255)'],
[1, 'rgb(240, 240, 255)']
]
},
borderWidth: 2,
plotBackgroundColor: 'rgba(255, 255, 255, .9)',
plotShadow: true,
plotBorderWidth: 1
},
title: {
style: {
color: '#000',
font: 'bold 16px "Trebuchet MS", Verdana, sans-serif'
}
},
subtitle: {
style: {
color: '#666666',
font: 'bold 12px "Trebuchet MS", Verdana, sans-serif'
}
},
xAxis: {
gridLineWidth: 1,
lineColor: '#000',
tickColor: '#000',
labels: {
style: {
color: '#000',
font: '11px Trebuchet MS, Verdana, sans-serif'
}
},
title: {
style: {
color: '#333',
fontWeight: 'bold',
fontSize: '12px',
fontFamily: 'Trebuchet MS, Verdana, sans-serif'
}
}
},
yAxis: {
minorTickInterval: 'auto',
lineColor: '#000',
lineWidth: 1,
tickWidth: 1,
tickColor: '#000',
labels: {
style: {
color: '#000',
font: '11px Trebuchet MS, Verdana, sans-serif'
}
},
title: {
style: {
color: '#333',
fontWeight: 'bold',
fontSize: '12px',
fontFamily: 'Trebuchet MS, Verdana, sans-serif'
}
}
},
legend: {
itemStyle: {
font: '9pt Trebuchet MS, Verdana, sans-serif',
color: 'black'
},
itemHoverStyle: {
color: '#039'
},
itemHiddenStyle: {
color: 'gray'
}
},
labels: {
style: {
color: '#99b'
}
},
navigation: {
buttonOptions: {
theme: {
stroke: '#CCCCCC'
}
}
}
};
// Apply the theme
var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
/**
* Skies theme for Highcharts JS
* @author Torstein Hønsi
*/
Highcharts.theme = {
colors: ["#514F78", "#42A07B", "#9B5E4A", "#72727F", "#1F949A", "#82914E", "#86777F", "#42A07B"],
chart: {
className: 'skies',
borderWidth: 0,
plotShadow: true,
plotBackgroundImage: 'http://www.highcharts.com/demo/gfx/skies.jpg',
plotBackgroundColor: {
linearGradient: [0, 0, 250, 500],
stops: [
[0, 'rgba(255, 255, 255, 1)'],
[1, 'rgba(255, 255, 255, 0)']
]
},
plotBorderWidth: 1
},
title: {
style: {
color: '#3E576F',
font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
}
},
subtitle: {
style: {
color: '#6D869F',
font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
}
},
xAxis: {
gridLineWidth: 0,
lineColor: '#C0D0E0',
tickColor: '#C0D0E0',
labels: {
style: {
color: '#666',
fontWeight: 'bold'
}
},
title: {
style: {
color: '#666',
font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
}
}
},
yAxis: {
alternateGridColor: 'rgba(255, 255, 255, .5)',
lineColor: '#C0D0E0',
tickColor: '#C0D0E0',
tickWidth: 1,
labels: {
style: {
color: '#666',
fontWeight: 'bold'
}
},
title: {
style: {
color: '#666',
font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
}
}
},
legend: {
itemStyle: {
font: '9pt Trebuchet MS, Verdana, sans-serif',
color: '#3E576F'
},
itemHoverStyle: {
color: 'black'
},
itemHiddenStyle: {
color: 'silver'
}
},
labels: {
style: {
color: '#3E576F'
}
}
};
// Apply the theme
var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
$(document)
.ready(
function() {
var options = {
chart : {
renderTo : 'hccontainer',
type : 'spline'
},
title : {
text : 'Snow depth at Vikjafjellet, Norway'
},
subtitle : {
text : 'Irregular time data in Highcharts JS'
},
xAxis : {
type : 'datetime',
},
yAxis : [ {
title : {
text : 'Snow depth (m)'
},
min : 0
}, {
} ],
tooltip : {
formatter : function() {
console.log(this.x);
return '<b>'
+ this.series.name
+ '</b><br/>'
+ Highcharts.dateFormat('%e. %b',
this.x) + ': ' + this.y + ' m';
}
},
series : [
{
name : 'Winter 2007-2008',
data : [ [ Date.UTC(2012, 9, 27), 0 ],
[ Date.UTC(2012, 10, 10), 0.6 ],
[ Date.UTC(2012, 10, 18), 0.7 ],
]
}, {
name : 'asd2',
data : [ {} ]
} ]
};
$.getJSON(
'#{request.contextPath}/rest/acc/boughtTimecount/27',
function(data) {
console.log(options.series);
console.log(data);
var series = data[0].series;
for (var serIdx = 0; serIdx < series.length; ++serIdx) {
var d = series[serIdx].data;
for (var i = 0; i < d.length; i++) {
if (d[i] instanceof Array) {
console
.log("Already array. not traversing");
} else {
series[serIdx].data[i] = d[i].item;
}
}
}
options.series = series;
console.log(options.series);
$("#hccontainer").highcharts(options);
}).done(function() {
console.log("second success");
}).fail(function() {
console.log("error");
}).always(function() {
console.log("complete");
});
});
......@@ -34,6 +34,7 @@
<h:body>
<!-- Javascript-lokalisaatiolippupuljausta -->
<script type="text/javascript">
$(document)
.ready(
......@@ -59,6 +60,7 @@
<header class="bgColor1 box">
<div id="header_left">
<h:link outcome="/index">
<c:choose>
<c:when test="#{sessionHandler.isInDevelopmentMode()}">
<img src="#{request.contextPath}/resources/templates/insomnia2/img/devel_logo.png" />
......@@ -107,17 +109,6 @@
<div id="menu">
<p:panelMenu model="#{primeMenuView.menuModel}" />
<h:link style="font-size: 10px;" rendered="#{readerView.shopToOthers}" outcome="/shop/showReaderEvents" value="Readers" />
<!-- <ui:fragment rendered="#{menuView.getMenu(2).size() > 1}">
<div id="right">
<ul>
<ui:repeat var="menuitem" value="#{menuView.getMenu(2)}">
<h:outputText rendered="#{!empty menuitem.header}" value="&lt;/ul>&lt;h1>#{i18n[menuitem.header]}&lt;/h1>&lt;ul>" escape="false" />
<li><h:link outcome="#{menuitem.outcome}" value="#{i18n[menuitem.navigation.key]}" styleClass="#{menuitem.selected?'active':''}" /></li>
</ui:repeat>
</ul>
</div>
</ui:fragment>
-->
</div>
</nav>
<section id="main" class="flex2">
......
......@@ -36,12 +36,7 @@
</plugins>
</build>
<repositories>
<repository>
<id>prime-repo</id>
<name>PrimeFaces Maven Repository</name>
<url>http://repository.primefaces.org</url>
<layout>default</layout>
</repository>
<repository>
<id>iudex</id>
<url>http://iudex.fi/maven/</url>
......@@ -81,7 +76,7 @@
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>4.0.RC1</version>
<version>4.0</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package fi.codecrew.moya.rest;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import fi.codecrew.moya.beans.PlaceGroupBeanLocal;
import fi.codecrew.moya.beans.PlaceMapBeanLocal;
import fi.codecrew.moya.beans.ProductBeanLocal;
import fi.codecrew.moya.model.AccountEvent;
import fi.codecrew.moya.model.Product;
import fi.codecrew.moya.rest.highcharts.HcSeries;
import fi.codecrew.moya.rest.highcharts.HcSeriesRoot;
@RequestScoped
@Path("/acc")
//@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
//@Produces({ MediaType.APPLICATION_JSON })
public class AccountEventRestView {
@EJB
private PlaceMapBeanLocal placemapbean;
@EJB
private PlaceGroupBeanLocal pgbean;
@EJB
private ProductBeanLocal productBean;
@GET
@Produces({ MediaType.APPLICATION_JSON })
@Path("/boughtTimecount/{productId}")
public ArrayList<HcSeriesRoot> boughtTimecount(@PathParam("productId") Integer productId) {
Product product = productBean.findById(productId);
SortedMap<Integer, SortedMap<Integer, SortedMap<Integer, Integer>>> counts = new TreeMap<>();
for (AccountEvent p : product.getAccountEvents())
{
Calendar d = p.getEventTime();
Integer year = d.get(Calendar.YEAR);
Integer month = d.get(Calendar.MONTH);
Integer day = d.get(Calendar.DAY_OF_MONTH);
SortedMap<Integer, SortedMap<Integer, Integer>> yearmap = counts.get(year);
if (yearmap == null) {
yearmap = new TreeMap<>();
counts.put(year, yearmap);
}
SortedMap<Integer, Integer> monthMap = yearmap.get(month);
if (monthMap == null) {
monthMap = new TreeMap<>();
yearmap.put(month, monthMap);
}
Integer dayValue = monthMap.get(day);
if (dayValue == null) {
dayValue = 0;
}
monthMap.put(day, dayValue += p.getQuantity().intValueExact());
}
boolean empty = true;
HcSeries data1 = new HcSeries("Daily");
HcSeries data2 = new HcSeries("Stacked");
Long data2Value = 0L;
for (Entry<Integer, SortedMap<Integer, SortedMap<Integer, Integer>>> ym : counts.entrySet()) {
Integer year = ym.getKey();
for (Entry<Integer, SortedMap<Integer, Integer>> mm : ym.getValue().entrySet()) {
Integer month = mm.getKey();
for (Entry<Integer, Integer> dm : mm.getValue().entrySet()) {
Integer day = dm.getKey();
// if (!empty) {
// data1.append(",");
// data2.append(",");
// } else {
// data1.append("\n");
// data2.append("\n");
// empty = false;
// }
Calendar c = Calendar.getInstance();
c.clear();
c.set(year, month, day);
//
data1.addDataentry(c, Long.valueOf(dm.getValue()));
data2.addDataentry(c, data2Value += dm.getValue());
//
// data1.append("\n [");
// data2.append("\n [");
//
// data1.append(c.getTimeInMillis());
// data2.append(c.getTimeInMillis());
//
// data1.append(", ");
// data2.append(", ");
//
// data1.append(dm.getValue()).append(" ] ");
// data2.append(data2Value += dm.getValue()).append(" ] ");
}
}
}
//
// StringBuilder retSb = new StringBuilder();
//
// retSb.append("[ { [ {\"name\": \"Set 1\", \"data\" : [ \n");
// retSb.append(data1.toString());
// retSb.append("\n ] } \n, {\"name\": \"Set 2\", \"data\": \n[\n");
// retSb.append(data2.toString());
// retSb.append("\n ] } ] \n} ]\n");
ArrayList<HcSeriesRoot> ret = new ArrayList<HcSeriesRoot>();
HcSeriesRoot seriesRoot = new HcSeriesRoot();
seriesRoot.getSeries().add(data1);
seriesRoot.getSeries().add(data2);
ret.add(seriesRoot);
ret.add(new HcSeriesRoot());
return ret;
}
}
package fi.codecrew.moya.rest;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import fi.codecrew.moya.beans.PlaceGroupBeanLocal;
import fi.codecrew.moya.beans.PlaceMapBeanLocal;
import fi.codecrew.moya.model.EventMap;
import fi.codecrew.moya.model.Place;
import fi.codecrew.moya.model.PlaceGroup;
@RequestScoped
@Path("/map")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
public class MapRestView {
@EJB
private PlaceMapBeanLocal placemapbean;
@EJB
private PlaceGroupBeanLocal pgbean;
@GET
@Path("/dateJson")
@Produces("text/javascript")
public String getAllCards() {
EventMap map = placemapbean.getActiveMap();
Map<Integer, Map<Integer, Map<Integer, Integer>>> counts = new HashMap<>();
for (Place p : map.getPlaces()) {
PlaceGroup pg = p.getGroup();
if (pg == null) {
continue;
}
Calendar d = pg.getCreated();
Integer year = d.get(Calendar.YEAR);
Integer month = d.get(Calendar.MONTH);
Integer day = d.get(Calendar.DAY_OF_MONTH);
Map<Integer, Map<Integer, Integer>> yearmap = counts.get(year);
if (yearmap == null) {
yearmap = new HashMap<>();
counts.put(year, yearmap);
}
Map<Integer, Integer> monthMap = yearmap.get(month);
if (monthMap == null) {
monthMap = new HashMap<>();
yearmap.put(month, monthMap);
}
Integer dayValue = monthMap.get(day);
if (dayValue == null) {
dayValue = 0;
}
monthMap.put(day, ++dayValue);
}
StringBuilder retSb = new StringBuilder("{ data : [\n");
boolean empty = true;
for (Entry<Integer, Map<Integer, Map<Integer, Integer>>> ym : counts.entrySet()) {
Integer year = ym.getKey();
for (Entry<Integer, Map<Integer, Integer>> mm : ym.getValue().entrySet()) {
Integer month = mm.getKey();
for (Entry<Integer, Integer> dm : mm.getValue().entrySet()) {
Integer day = dm.getKey();
if (!empty)
{
retSb.append(",");
} else {
empty = false;
}
retSb.append(" [Date.UTC(")
.append(year).append(", ")
.append(month).append(", ")
.append(day).append("), ")
.append(dm.getValue()).append(" ] \n");
}
}
}
retSb.append("\n] }\n");
return retSb.toString();
}
}
......@@ -8,12 +8,20 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import fi.codecrew.moya.beans.ReaderBeanLocal;
import fi.codecrew.moya.beans.UserBeanLocal;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.ReaderEvent;
import fi.codecrew.moya.rest.pojo.EventUserRestPojo;
import fi.codecrew.moya.rest.pojo.ReaderEventRestPojo;
import fi.codecrew.moya.rest.pojo.ReaderEventRestRoot;
import fi.codecrew.moya.rest.pojo.ReaderRestPojo;
import fi.codecrew.moya.rest.pojo.ReaderRestRoot;
import fi.codecrew.moya.rest.pojo.UserPermissionRestPojo;
@RequestScoped
@Path("/reader")
......@@ -24,6 +32,9 @@ public class ReaderRestView {
@EJB
private ReaderBeanLocal readerbean;
@EJB
private UserBeanLocal userbean;
@GET
@Path("/List")
public ReaderRestRoot getReaderList()
......@@ -45,9 +56,37 @@ public class ReaderRestView {
// }
@GET
@Path("/EventRole/{reader}/{roleid}")
public void eventRole(@PathParam("reader") String reader, @PathParam("roleid") String roleId) {
@Path("/EventRole/{reader}/{tagId}/{roleid}")
public Response eventRole(@PathParam("reader") String reader, @PathParam("tagId") String tag, @PathParam("roleid") Integer roleId) {
ReaderEvent ret = readerbean.checkTag(reader, tag);
ResponseBuilder builder = null;
if (roleId == null || roleId.equals(0))
{
builder = Response.status(Status.BAD_REQUEST);
builder.entity("role ID is required!");
builder.type(MediaType.TEXT_PLAIN);
}
if (builder == null)
{
if (ret == null || ret.getPrintedCard() == null) {
builder = Response.status(Status.NOT_ACCEPTABLE);
builder.entity("No card found for uid.");
builder.type(MediaType.TEXT_PLAIN);
} else {
EventUser user = ret.getPrintedCard().getUser();
boolean found = userbean.isUserInRole(user, roleId);
if (found) {
builder = Response.status(Status.OK);
} else {
builder = Response.status(Status.FORBIDDEN);
}
builder.entity(new UserPermissionRestPojo(new EventUserRestPojo(user), found));
}
}
return builder.build();
}
@GET
......
package fi.codecrew.moya.rest.highcharts;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
public class HcSeries implements Serializable {
/**
*
*/
private static final long serialVersionUID = -7588127658185575480L;
private String name;
private ArrayList<Long[]> data = new ArrayList<>();
public HcSeries() {
super();
}
public HcSeries(String string) {
super();
name = string;
}
@XmlElement
public String getName() {
return name;
}
@XmlElement(name = "data")
public Long[][] getDataArray()
{
return data.toArray(new Long[data.size()][]);
}
public void setName(String name) {
this.name = name;
}
@XmlTransient
public ArrayList<Long[]> getData() {
return data;
}
public void setData(ArrayList<Long[]> data) {
this.data = data;
}
public void addDataentry(Calendar c, Long value) {
getData().add(new Long[] { c.getTimeInMillis(), value });
}
}
package fi.codecrew.moya.rest.highcharts;
import java.io.Serializable;
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class HcSeriesRoot implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6638471281639352627L;
private String foo = "asdasd";
// @XmlElement(name = "series")
// @XmlElementWrapper(name = "serie")
private ArrayList<HcSeries> series = new ArrayList<>();
public ArrayList<HcSeries> getSeries() {
return series;
}
public void setSeries(ArrayList<HcSeries> series) {
this.series = series;
}
}
......@@ -15,6 +15,18 @@ public class EventUserRestPojo {
this.user = user;
}
@XmlElement(name = "nick")
public String getUsername()
{
return user.getUser().getNick();
}
@XmlElement(name = "login")
public String getLogin()
{
return user.getUser().getLogin();
}
@XmlElement(name = "eventuserId")
public Integer getEventuserId()
{
......
package fi.codecrew.moya.rest.pojo;
import javax.xml.bind.annotation.XmlElement;
public class UserPermissionRestPojo {
public UserPermissionRestPojo(EventUserRestPojo eventUserRestPojo, boolean granted)
{
this();
this.user = eventUserRestPojo;
this.accessGranted = granted;
}
public UserPermissionRestPojo()
{
super();
}
public boolean isAccessGranted() {
return accessGranted;
}
public void setAccessGranted(boolean accessGranted) {
this.accessGranted = accessGranted;
}
public EventUserRestPojo getUser() {
return user;
}
public void setUser(EventUserRestPojo user) {
this.user = user;
}
@XmlElement(name = "user")
private EventUserRestPojo user;
@XmlElement(name = "accessGranted")
private boolean accessGranted = false;
}
......@@ -11,7 +11,6 @@ import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.AccountEventBeanLocal;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.beans.PlaceBeanLocal;
import fi.codecrew.moya.beans.PlaceMapBeanLocal;
......@@ -40,8 +39,6 @@ public class MapView extends GenericCDIView {
@EJB
private transient EventBeanLocal eventBean;
private BigDecimal balance;
@EJB
private transient AccountEventBeanLocal acbean;
private static final Logger logger = LoggerFactory.getLogger(MapView.class);
......
......@@ -14,7 +14,6 @@ import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.AccountEventBeanLocal;
import fi.codecrew.moya.beans.PlaceBeanLocal;
import fi.codecrew.moya.beans.UserBeanLocal;
import fi.codecrew.moya.enums.apps.MapPermission;
......@@ -56,8 +55,6 @@ public class PlaceView extends GenericCDIView {
private String searchuser;
private transient ListDataModel<User> userlist;
@EJB
private transient AccountEventBeanLocal acbean;
public boolean canEdit() {
return permbean.hasPermission(MapPermission.MANAGE_MAPS);
......@@ -115,7 +112,7 @@ public class PlaceView extends GenericCDIView {
if (!placebean.reservePlace(place, user)) {
this.addFaceMessage("mapView.errorWhenReservingPlace");
}
} else {
if (balance.compareTo(BigDecimal.ZERO) > 0) {
addFaceMessage("mapView.notEnoughCreditsToReserve");
......
......@@ -13,7 +13,6 @@ import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.AccountEventBeanLocal;
import fi.codecrew.moya.beans.BillBeanLocal;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.beans.FoodWaveBeanLocal;
......@@ -42,9 +41,6 @@ public class FoodWaveFoodView extends GenericCDIView {
EventBeanLocal eventBean;
@EJB
private AccountEventBeanLocal accountEventBean;
@EJB
private BillBeanLocal billBean;
private FoodWave foodWave = null;
......
......@@ -17,7 +17,6 @@ import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.AccountEventBeanLocal;
import fi.codecrew.moya.beans.BillBeanLocal;
import fi.codecrew.moya.beans.EventBeanLocal;
import fi.codecrew.moya.beans.FoodWaveBeanLocal;
......@@ -54,9 +53,6 @@ public class FoodWaveView extends GenericCDIView {
@EJB
private BillBeanLocal billbean;
@EJB
private AccountEventBeanLocal accountEventBean;
private FoodWave selectedFoodWave = null;
private Date startDate;
......@@ -244,7 +240,7 @@ public class FoodWaveView extends GenericCDIView {
public String deliverAccountEvent() {
if (getAccountEventLines().isRowAvailable()) {
AccountEvent e = getAccountEventLines().getRowData();
e = accountEventBean.markDelivered(e, Calendar.getInstance());
e = productbeanlocal.markDelivered(e, Calendar.getInstance());
foodWaveId = selectedFoodWave.getId();
selectedFoodWave = null;
initFoodWaveOrderList();
......
......@@ -28,7 +28,7 @@ public class RfidView extends GenericCDIView {
private static final Logger logger = LoggerFactory.getLogger(RfidView.class);
public void readTag() {
ReaderEvent revent = readerbean.checkTag(reader, tag, hash);
ReaderEvent revent = readerbean.checkTag(reader, tag);
logger.debug("at view Got readerevent from bean: {}", revent);
}
......
......@@ -5,7 +5,7 @@ import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import fi.codecrew.moya.beans.AccountEventBeanLocal;
import fi.codecrew.moya.beans.ProductBeanLocal;
import fi.codecrew.moya.enums.apps.UserPermission;
import fi.codecrew.moya.model.AccountEvent;
import fi.codecrew.moya.web.cdiview.GenericCDIView;
......@@ -20,7 +20,7 @@ public class AccountEventView extends GenericCDIView {
private static final long serialVersionUID = -1873486276276870190L;
@EJB
private transient AccountEventBeanLocal accounteventbean;
private transient ProductBeanLocal productBean;
private AccountEvent accountevent;
private Integer accountid;
......@@ -32,7 +32,7 @@ public class AccountEventView extends GenericCDIView {
public void initView() {
accountevent = accounteventbean.find(getAccountid());
accountevent = productBean.find(getAccountid());
if (accountevent != null && requirePermissions(permbean.isCurrentUser(accountevent.getUser()) || permbean.hasPermission(UserPermission.VIEW_ACCOUNTEVENTS))) {
userview.setUser(accountevent.getUser());
beginConversation();
......@@ -46,14 +46,14 @@ public class AccountEventView extends GenericCDIView {
public String save()
{
super.addFaceMessage("accountevent.saved");
accountevent = accounteventbean.merge(accountevent);
accountevent = productBean.merge(accountevent);
userview.setUser(accountevent.getUser());
return null;
}
public String delete()
{
userview.setUser(accounteventbean.delete(accountevent));
userview.setUser(productBean.delete(accountevent));
return "/useradmin/accountEvents";
}
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!