commit 0df2670a2c62d13cd2d5a5f61d93e28d5647b2e1 Author: Christophe Coenraets Date: Thu Jul 13 14:14:38 2017 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93d955a --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.classpath +.DS_Store +.sfdx +.project +.salesforce +node_modules +.idea +.tern-project +.settings +selenium-client-jars/ +test/artifacts \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..82e085c --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +## Northern Trail Outfitters Sample App + +See [this blog post](https://developer.salesforce.com/blogs) for details and installation instructions. diff --git a/config/project-scratch-def.json b/config/project-scratch-def.json new file mode 100644 index 0000000..d484e0e --- /dev/null +++ b/config/project-scratch-def.json @@ -0,0 +1,7 @@ +{ + "orgName": "ccoenraets Company", + "edition": "Developer", + "orgPreferences" : { + "enabled": ["S1DesktopEnabled"] + } +} diff --git a/data/sample-data-Merchandise__c-plan.json b/data/sample-data-Merchandise__c-plan.json new file mode 100644 index 0000000..097f856 --- /dev/null +++ b/data/sample-data-Merchandise__c-plan.json @@ -0,0 +1,10 @@ +[ + { + "sobject": "Merchandise__c", + "saveRefs": true, + "resolveRefs": false, + "files": [ + "sample-data-Merchandise__cs.json" + ] + } +] \ No newline at end of file diff --git a/data/sample-data-Merchandise__cs.json b/data/sample-data-Merchandise__cs.json new file mode 100644 index 0000000..7add7b5 --- /dev/null +++ b/data/sample-data-Merchandise__cs.json @@ -0,0 +1,114 @@ +{ + "records": [ + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef1" + }, + "Name": "BOREALIS BACKPACK", + "Description__c": "Free of embellishment, this sleek, 29-liter daypack boasts two large zip pockets so you can stash gear quickly and hit the road. The main compartment features a padded laptop sleeve (fits most 15\" laptops), and an almost equally large secondary zip pocket with built-in organizational sleeves. Bungee cord on face of pack lets you store additional gear, or cinch down contents inside. Updated shoulder straps and back panel.", + "Price__c": 89, + "Category__c": "Gear", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/4004100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef2" + }, + "Name": "WOMEN'S LEONIDAS JACKET", + "Description__c": "Persevere through wet conditions in remote locations with the help of our alpine workhorse, a waterproof soft shell with leakproof fully-taped seams. Four-way stretch HyVent 2L technology provides durable, multi-layer waterproofing that remains breathable during stages of intense climbing. Fully adjustable hood with laminated brim is helmet compatible for extra coverage. Cuffs adjust with non-abrasive molded tabs.", + "Price__c": 230, + "Category__c": "Womens", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products370/2011100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef3" + }, + "Name": "MEN'S QUANTUM JACKET", + "Description__c": "Reach new heights during aerobic assaults on the summit wearing this lightweight Polartec Thermal Pro gridded fleece mid-layer with an exceptional warmth-to-weight ratio. Hybrid construction strategically places Polartec Power Dry under the arms, on the upper back, and down the forearms for improved moisture management. Zippered handwarmer pockets are designed to remain accessible while you're wearing a climbing harness or a pack.", + "Price__c": 160, + "Category__c": "Mens", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/1002100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef4" + }, + "Name": "WOMEN'S ARCTIC PARKA", + "Description__c": "Even if you don't live in the Arctic, it probably feels like you do on some winter days. This trench coat combines waterproof, breathable, seam sealed protection via HyVent nylon fabric at exterior with thermal 550 fill down insulation to create a resilient barrier during winter weather. Attached, adjustable hood features two cinch-cords to secure a close fit (removable faux fur trim), and five pockets throughout creates plenty of space to stash essentials.", + "Price__c": 330, + "Category__c": "Womens", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/2007100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef5" + }, + "Name": "BOYS' PRINTED RESOLVE JACKET", + "Description__c": "He'll splish-splash his way through the worst weather, yet remain bone dry, while wearing this waterproof boys' hooded jacket. Durable HyVent 2L technology features multi-layer waterproofing that's also highly breathable for improved temperature regulation. A mesh lining improves the overall breathability of this seam-sealed rain jacket. The full-length front zipper is protected by a Velcro stormflap to shut out wind and rain. Finished with a brushed collar lining that's soft against the skin when the jacket is fully zipped. Hood stows away in the collar when not in use.", + "Price__c": 75, + "Category__c": "Kids", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/3006100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef6" + }, + "Name": "2-METER DOME", + "Description__c": "\"If you are planning on spending long periods of time in the mountains, this is the dream base camp tent. This 2-Meter Dome was my living room, bed room, kitchen, and art studio for two months in the Himalayas. It was so cozy I almost didn't want to leave.\" - Cedar Wright, The North Face Athlete, Rock ClimberThe ultimate eight-person expedition base camp tent, the 2-Meter Dome is extremely durable and efficient in merciless environs such as the Himalayas and Antarctica. Setting the standard for unrivaled performance in major expeditions, this is the tent top mountaineers trust in critical conditions.", + "Price__c": 5000, + "Category__c": "Gear", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/4437100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef7" + }, + "Name": "JESTER BACKPACK", + "Description__c": "No one will call you a fool with the Jester on your back. Designed with two large zip compartments, this versatile 27-liter pack features a front accessory zip pocket with an internal organization sleeve to stash smaller items. Bungee cords crisscross across this pack's face to provide a stellar spot to loop in a rain jacket, or wiffle ball bat.", + "Price__c": 65, + "Category__c": "Gear", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/4003100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef8" + }, + "Name": "MINIBUS 3", + "Description__c": "Cutting-edge tent design for backpackers features spacious internal volume through tall vertical side walls on the interior and tons of usable vestibule space. Leading the industry in terms of interior volume, this three-person tent also features comprehensive color coded poles for easy setup, refined venting options, and a large front window to watch passing raccoons.", + "Price__c": 399, + "Category__c": "Gear", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/4412100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef9" + }, + "Name": "MEN'S LEONIDAS JACKET", + "Description__c": "Persevere through wet conditions in remote locations with the help of our alpine workhorse, a waterproof soft shell with leak-proof fully taped seams. Four-way stretch HyVent 2L technology provides durable, multi-layer waterproofing that remains breathable during stages of intense climbing. Fully adjustable hood with laminated brim is helmet compatible for extra coverage. Cuffs adjust with non-abrasive molded tabs.", + "Price__c": 230, + "Category__c": "Mens", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/1008100.jpg" + }, + { + "attributes": { + "type": "Merchandise__c", + "referenceId": "Merchandise__cRef10" + }, + "Name": "GIRLS' MOUNTAIN VIEW TRICLIMATE JACKET", + "Description__c": "It's all about the power of three: this versatile jacket combines a waterproof, breathable, fully seam sealed HyVent shell with a removable, insulated interior jacket for adaptable protection in any condition. Adjustable drawcord lock system accessible through interior pockets. Traditional color blocking underneath arms creates classic alpine style.", + "Price__c": 140, + "Category__c": "Kids", + "Picture_URL__c": "https://s3-us-west-2.amazonaws.com/nto-products/products1110/3031100.jpg" + } + ] +} \ No newline at end of file diff --git a/force-app/main/default/applications/Northern_Trail.app-meta.xml b/force-app/main/default/applications/Northern_Trail.app-meta.xml new file mode 100644 index 0000000..6f29dca --- /dev/null +++ b/force-app/main/default/applications/Northern_Trail.app-meta.xml @@ -0,0 +1,22 @@ + + + + #027FB3 + nto_logo + 1 + + Connecting to our customers in a whole new way + Large + + Standard + standard-home + standard-Account + standard-Contact + Merchandising_Mix__c + Merchandise__c + standard-File + standard-Opportunity + standard-Event + Lightning + Northern_Trail_UtilityBar + diff --git a/force-app/main/default/aura/CategorySelector/CategorySelector.cmp b/force-app/main/default/aura/CategorySelector/CategorySelector.cmp new file mode 100755 index 0000000..e9e82b4 --- /dev/null +++ b/force-app/main/default/aura/CategorySelector/CategorySelector.cmp @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/CategorySelector/CategorySelector.cmp-meta.xml b/force-app/main/default/aura/CategorySelector/CategorySelector.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/CategorySelector/CategorySelector.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/CategorySelector/CategorySelector.css b/force-app/main/default/aura/CategorySelector/CategorySelector.css new file mode 100755 index 0000000..1a9120d --- /dev/null +++ b/force-app/main/default/aura/CategorySelector/CategorySelector.css @@ -0,0 +1,3 @@ +.THIS { + max-width: 436px; +} \ No newline at end of file diff --git a/force-app/main/default/aura/CategorySelector/CategorySelectorController.js b/force-app/main/default/aura/CategorySelector/CategorySelectorController.js new file mode 100755 index 0000000..762a993 --- /dev/null +++ b/force-app/main/default/aura/CategorySelector/CategorySelectorController.js @@ -0,0 +1,20 @@ +({ + afterScriptsLoaded : function(component, event, helper) { + var assetClasses = window.DataCache.getData("assetClasses"); + if (assetClasses) { + console.log('product categories retrieved from custom cache'); + component.set("v.categories", assetClasses); + } else { + helper.loadCategories(component); + } + }, + + changeHandler : function(component, event, helper) { + var changeEvent = component.getEvent("onchange"); + changeEvent.setParams({ + "value": component.get("v.selectedValue") + }); + changeEvent.fire(); + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/CategorySelector/CategorySelectorHelper.js b/force-app/main/default/aura/CategorySelector/CategorySelectorHelper.js new file mode 100755 index 0000000..1b01f16 --- /dev/null +++ b/force-app/main/default/aura/CategorySelector/CategorySelectorHelper.js @@ -0,0 +1,15 @@ +({ + loadCategories: function (component) { + var action = component.get("c.getCategories"); + action.setCallback(this, function (response) { + var categories = response.getReturnValue(); + if (categories) { + categories.unshift(""); + window.DataCache.setData("categories", categories); + component.set("v.categories", categories); + } + }); + $A.enqueueAction(action); + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.cmp b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.cmp new file mode 100755 index 0000000..808293c --- /dev/null +++ b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.cmp @@ -0,0 +1,29 @@ + + + + + + + + +
All Available Merchandise
+ + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.cmp-meta.xml b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.css b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.css new file mode 100755 index 0000000..f2410e9 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.css @@ -0,0 +1,7 @@ +.THIS .slider { + margin-top: -14px; +} + +.THIS .right-padding { + padding-right: 12px; +} \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.design b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.design new file mode 100755 index 0000000..573bd32 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.design @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.svg b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.svg new file mode 100755 index 0000000..c01a506 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilter.svg @@ -0,0 +1,12 @@ + + + filter + filter + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilterController.js b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilterController.js new file mode 100755 index 0000000..1407f8f --- /dev/null +++ b/force-app/main/default/aura/MerchandiseFilter/MerchandiseFilterController.js @@ -0,0 +1,19 @@ +({ + + searchKeyChangeHandler : function(component, event) { + var merchandiseFilterChangeEvent = $A.get("e.c:MerchandiseFilterChange"); + merchandiseFilterChangeEvent.setParams({ + "searchKey": event.getParam("value") + }); + merchandiseFilterChangeEvent.fire(); + }, + + categoryChangeHandler : function(component, event) { + var merchandiseFilterChangeEvent = $A.get("e.c:MerchandiseFilterChange"); + merchandiseFilterChangeEvent.setParams({ + "category": event.getParam("value") + }); + merchandiseFilterChangeEvent.fire(); + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseFilterChange/MerchandiseFilterChange.evt b/force-app/main/default/aura/MerchandiseFilterChange/MerchandiseFilterChange.evt new file mode 100644 index 0000000..b9daf6c --- /dev/null +++ b/force-app/main/default/aura/MerchandiseFilterChange/MerchandiseFilterChange.evt @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseFilterChange/MerchandiseFilterChange.evt-meta.xml b/force-app/main/default/aura/MerchandiseFilterChange/MerchandiseFilterChange.evt-meta.xml new file mode 100644 index 0000000..21eb3e5 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseFilterChange/MerchandiseFilterChange.evt-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Event Bundle + diff --git a/force-app/main/default/aura/MerchandiseList/MerchandiseList.cmp b/force-app/main/default/aura/MerchandiseList/MerchandiseList.cmp new file mode 100755 index 0000000..63fbb8f --- /dev/null +++ b/force-app/main/default/aura/MerchandiseList/MerchandiseList.cmp @@ -0,0 +1,28 @@ + + + + + + + + + + + + + +
+ + + + + + + + + +
+ +
\ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseList/MerchandiseList.cmp-meta.xml b/force-app/main/default/aura/MerchandiseList/MerchandiseList.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseList/MerchandiseList.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/MerchandiseList/MerchandiseList.css b/force-app/main/default/aura/MerchandiseList/MerchandiseList.css new file mode 100755 index 0000000..da63284 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseList/MerchandiseList.css @@ -0,0 +1,7 @@ +.THIS { + position: relative; +} + +.THIS .slds-app-launcher__tile { + margin: 0 0 1rem 0; +} \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseList/MerchandiseList.design b/force-app/main/default/aura/MerchandiseList/MerchandiseList.design new file mode 100755 index 0000000..65495d6 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseList/MerchandiseList.design @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseList/MerchandiseList.svg b/force-app/main/default/aura/MerchandiseList/MerchandiseList.svg new file mode 100755 index 0000000..869bda4 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseList/MerchandiseList.svg @@ -0,0 +1,11 @@ + + + List + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseList/MerchandiseListController.js b/force-app/main/default/aura/MerchandiseList/MerchandiseListController.js new file mode 100755 index 0000000..08e89d4 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseList/MerchandiseListController.js @@ -0,0 +1,46 @@ +({ + doInit: function(component, event, helper) { + var filterObject = { + searchKey: '', + category: '' + }; + component.set("v.filterObject", filterObject); + helper.loadMerchandise(component); + }, + + onPreviousPage: function(component, event, helper) { + var page = component.get("v.page") || 1; + page = page - 1; + helper.loadMerchandise(component, page); + }, + + onNextPage: function(component, event, helper) { + var page = component.get("v.page") || 1; + page = page + 1; + helper.loadMerchandise(component, page); + }, + + filterChangeHandler: function(component, event, helper) { + var filterObject = component.get("v.filterObject"); + if (event.getParam("searchKey") !== undefined) { + filterObject.searchKey = event.getParam("searchKey"); + } + if (event.getParam("category") !== undefined) { + filterObject.category = event.getParam("category"); + } + helper.loadMerchandise(component); + }, + + rangeChange: function(component, event, helper) { + var filterName = event.getParam("filterName"); + var minValue = event.getParam("minValue"); + var maxValue = event.getParam("maxValue"); + var filterObject = component.get("v.filterObject"); + if (filterName === 'MSRP') { + filterObject.minPrice = minValue; + filterObject.maxPrice = maxValue; + } + helper.loadMerchandise(component); + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseList/MerchandiseListHelper.js b/force-app/main/default/aura/MerchandiseList/MerchandiseListHelper.js new file mode 100755 index 0000000..63bfdf0 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseList/MerchandiseListHelper.js @@ -0,0 +1,22 @@ +({ + loadMerchandise : function(component, page) { + var action = component.get("c.getMerchandise"); + action.setStorable(); + var pageSize = component.get("v.pageSize"); + action.setParams({ + "filters": JSON.stringify(component.get("v.filterObject")), + "pageSize": pageSize, + "pageNumber": page || 1 + }); + action.setCallback(this, function(response) { + console.log('# getProducts callback %f', (performance.now() - startTime)); + var result = response.getReturnValue(); + component.set("v.items", result.items); + component.set("v.page", result.page); + component.set("v.total", result.total); + component.set("v.pages", Math.ceil(result.total/pageSize)); + }); + var startTime = performance.now(); + $A.enqueueAction(action); + } +}) \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.cmp b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.cmp new file mode 100755 index 0000000..97af4a6 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.cmp @@ -0,0 +1,56 @@ + + + + + + + + + + + + +
+ + + + + + + +

Total MSRP

+

+ $0 +

+
+ +

Products

+

{!v.mixItems.length}

+
+ +

Qty

+

{!v.totalQty}

+
+ + + + + +
+
+
+ +
+ + + + + + + +
+
+ +
\ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.cmp-meta.xml b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.css b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.css new file mode 100755 index 0000000..9c7f9ae --- /dev/null +++ b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.css @@ -0,0 +1,33 @@ +.THIS { + margin-top: -20px; +} + +.THIS .header { + padding: 20px 20px 20px 0; + border-top: solid 1px #D8DDE6; +} + +.THIS .header-fields>div { + padding-right: 20px; +} + +.THIS .slds-icon_container { + border-radius: 2px; +} + +.THIS .total-msrp { + width: 80px; + color: #FF6600; +} + +.THIS .drop-zone { + box-sizing: border-box; + min-height: 200px; + border-width: 2px; + border-style: dashed; + border-color: transparent; +} + +.THIS .drop-zone.active { + border-color: #D8DDE6; +} \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.design b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.design new file mode 100755 index 0000000..e674ee2 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.design @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.svg b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.svg new file mode 100755 index 0000000..91fec1b --- /dev/null +++ b/force-app/main/default/aura/MerchandiseMix/MerchandiseMix.svg @@ -0,0 +1,12 @@ + + + filter + Mix. + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseMix/MerchandiseMixController.js b/force-app/main/default/aura/MerchandiseMix/MerchandiseMixController.js new file mode 100755 index 0000000..a0f2644 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseMix/MerchandiseMixController.js @@ -0,0 +1,52 @@ +({ + doInit : function(component, event, helper) { + var mixId = component.get("v.recordId"); + helper.loadMixItems(component, mixId); + }, + + dropHandler : function(component, event, helper) { + event.preventDefault(); + var cmpTarget= component.find("dropZone"); + $A.util.removeClass(cmpTarget, 'active'); + var mixItems = component.get("v.mixItems"); + var merchandise = JSON.parse(event.dataTransfer.getData("merchandise")); + var mixItem = { + Merchandising_Mix__c: component.get("v.recordId"), + Merchandise__c: merchandise.Id, + Qty__c: 10, + Merchandise__r: { + Id: merchandise.Id, + Name: merchandise.Name, + Price__c: merchandise.Price__c, + Category__c: merchandise.Category__c, + Picture_URL__c: merchandise.Picture_URL__c + } + }; + mixItems.push(mixItem); + helper.addItem(component, mixItem); + component.set("v.mixItems", mixItems); + }, + + dragOverHandler : function(component, event) { + event.preventDefault(); + var cmpTarget= component.find("dropZone"); + $A.util.addClass(cmpTarget, 'active'); + }, + + dragLeaveHandler : function(component, event){ + event.preventDefault(); + var cmpTarget= component.find("dropZone"); + $A.util.removeClass(cmpTarget, 'active'); + }, + + mixItemDeleteHandler : function(component, event, helper) { + var mixItem = event.getParam("mixItem"); + helper.removeItem(component, mixItem); + }, + + mixItemChangeHandler : function(component, event, helper) { + var mixItem = event.getParam("mixItem"); + helper.updateItem(component, mixItem); + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseMix/MerchandiseMixHelper.js b/force-app/main/default/aura/MerchandiseMix/MerchandiseMixHelper.js new file mode 100755 index 0000000..d48e98c --- /dev/null +++ b/force-app/main/default/aura/MerchandiseMix/MerchandiseMixHelper.js @@ -0,0 +1,82 @@ +({ + loadMixItems : function(component, mixId) { + var action = component.get("c.getMixItems"); + action.setStorable(); + action.setParams({ + "mixId": mixId + }); + action.setCallback(this, function(response) { + var result = response.getReturnValue(); + component.set("v.mixItems", result); + this.calculateMix(component); + }); + $A.enqueueAction(action); + }, + + addItem : function(component, mixItem) { + var action = component.get("c.addMixItem"); + action.setParams({ + "mixId": mixItem.Merchandising_Mix__c, + "productId": mixItem.Merchandise__c, + "qty": mixItem.Qty__c + }); + action.setCallback(this, function(response) { + var result = response.getReturnValue(); + mixItem.Id = result.Id; + this.calculateMix(component); + }); + $A.enqueueAction(action); + }, + + updateItem : function(component, mixItem) { + var action = component.get("c.updateMixItem"); + action.setParams({ + "mixItem": mixItem + }); + action.setCallback(this, function(response) { + this.calculateMix(component); + }); + $A.enqueueAction(action); + }, + + removeItem : function(component, mixItem) { + var action = component.get("c.removeMixItem"); + action.setParams({ + "mixItemId": mixItem.Id + }); + action.setCallback(this, function(response) { + var result = response.getReturnValue(); + var mixItems = component.get("v.mixItems"); + for (var i=0; i + + + + + + +
+ +
{!v.record.Name}
+
+ + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.cmp-meta.xml b/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.cmp-meta.xml new file mode 100644 index 0000000..d7e1e13 --- /dev/null +++ b/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.css b/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.css new file mode 100644 index 0000000..ef4babe --- /dev/null +++ b/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.css @@ -0,0 +1,3 @@ +.THIS { + text-align: center; +} diff --git a/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.svg b/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.svg new file mode 100644 index 0000000..4bdd21e --- /dev/null +++ b/force-app/main/default/aura/MerchandisePicture/MerchandisePicture.svg @@ -0,0 +1,15 @@ + + + + Group + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandisePicture/MerchandisePictureController.js b/force-app/main/default/aura/MerchandisePicture/MerchandisePictureController.js new file mode 100644 index 0000000..b235899 --- /dev/null +++ b/force-app/main/default/aura/MerchandisePicture/MerchandisePictureController.js @@ -0,0 +1,5 @@ +({ + myAction : function(component, event, helper) { + + } +}) diff --git a/force-app/main/default/aura/MerchandisePicture/MerchandisePictureHelper.js b/force-app/main/default/aura/MerchandisePicture/MerchandisePictureHelper.js new file mode 100644 index 0000000..f8a77e3 --- /dev/null +++ b/force-app/main/default/aura/MerchandisePicture/MerchandisePictureHelper.js @@ -0,0 +1,5 @@ +({ + helperMethod : function() { + + } +}) diff --git a/force-app/main/default/aura/MerchandisePicture/MerchandisePictureRenderer.js b/force-app/main/default/aura/MerchandisePicture/MerchandisePictureRenderer.js new file mode 100644 index 0000000..3a11ff5 --- /dev/null +++ b/force-app/main/default/aura/MerchandisePicture/MerchandisePictureRenderer.js @@ -0,0 +1,5 @@ +({ + +// Your renderer method overrides go here + +}) diff --git a/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.cmp b/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.cmp new file mode 100644 index 0000000..a289855 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.cmp @@ -0,0 +1,23 @@ + + + + + + + +
+ + + + + + + + + +
MSRP:
+
+
+
+ +
\ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.cmp-meta.xml b/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.cmp-meta.xml new file mode 100644 index 0000000..2dbe44e --- /dev/null +++ b/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.css b/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.css new file mode 100644 index 0000000..a2378f2 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseTile/MerchandiseTile.css @@ -0,0 +1,33 @@ +.THIS { + cursor: -webkit-grab; + border-bottom: solid 1px #d8dde6; + width: 100%; +} + +.THIS a { + color: inherit; +} + +.THIS:active { + cursor: -webkit-grabbing; +} + +.THIS img.merchandise { + height: auto; + min-height: 50px; + width: 50px; +} + +.THIS img{ + max-width: initial; +} + +.THIS .price, +.THIS .title { + font-weight: bold; + text-transform: uppercase; +} + +.THIS .price { + color: #FF6600; +} \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseTile/MerchandiseTileController.js b/force-app/main/default/aura/MerchandiseTile/MerchandiseTileController.js new file mode 100644 index 0000000..e2eb631 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseTile/MerchandiseTileController.js @@ -0,0 +1,15 @@ +({ + titleClickHandler: function(component) { + var navEvt = $A.get("e.force:navigateToSObject"); + navEvt.setParams({ + "recordId": component.get("v.merchandise").Id, + "slideDevName": "detail" + }); + navEvt.fire(); + }, + + dragStart : function(component, event) { + var merchandise = component.get("v.merchandise"); + event.dataTransfer.setData("merchandise", JSON.stringify(merchandise)); + } +}) \ No newline at end of file diff --git a/force-app/main/default/aura/MerchandiseTile/MerchandiseTileHelper.js b/force-app/main/default/aura/MerchandiseTile/MerchandiseTileHelper.js new file mode 100644 index 0000000..f8a77e3 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseTile/MerchandiseTileHelper.js @@ -0,0 +1,5 @@ +({ + helperMethod : function() { + + } +}) diff --git a/force-app/main/default/aura/MerchandiseTile/MerchandiseTileRenderer.js b/force-app/main/default/aura/MerchandiseTile/MerchandiseTileRenderer.js new file mode 100644 index 0000000..3a11ff5 --- /dev/null +++ b/force-app/main/default/aura/MerchandiseTile/MerchandiseTileRenderer.js @@ -0,0 +1,5 @@ +({ + +// Your renderer method overrides go here + +}) diff --git a/force-app/main/default/aura/MixChart/MixChart.cmp b/force-app/main/default/aura/MixChart/MixChart.cmp new file mode 100755 index 0000000..f7950de --- /dev/null +++ b/force-app/main/default/aura/MixChart/MixChart.cmp @@ -0,0 +1,62 @@ + + + + + + + + + + +
+ +
+
+ + + +
+ + + Womens + + + + +
+ + + Mens + + + + +
+ + + Kids + + + + + + +
+ + + Gear + + + + +
+ + + Electronics + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MixChart/MixChart.cmp-meta.xml b/force-app/main/default/aura/MixChart/MixChart.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/MixChart/MixChart.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/MixChart/MixChart.css b/force-app/main/default/aura/MixChart/MixChart.css new file mode 100755 index 0000000..80c3d0c --- /dev/null +++ b/force-app/main/default/aura/MixChart/MixChart.css @@ -0,0 +1,37 @@ +.THIS .chart{ + position: relative; + text-align: center; + width: 100px; + height: 60px; +} + + + +.THIS .slds-text-heading--medium { + margin-bottom: 12px; +} + +.THIS .legend { + width: 10px; + height: 10px; +} + +.THIS .legend.womens { + background-color: rgba(126,139,228,.8); +} + +.THIS .legend.mens { + background-color: rgba(84,105,141,.8); +} + +.THIS .legend.kids { + background-color: rgba(254,143,96,.8); +} + +.THIS .legend.gear { + background-color: rgba(125,195,125,.8); +} + +.THIS .legend.electronics { + background-color: rgba(52,190,205,.8); +} \ No newline at end of file diff --git a/force-app/main/default/aura/MixChart/MixChartController.js b/force-app/main/default/aura/MixChart/MixChartController.js new file mode 100755 index 0000000..b7b547c --- /dev/null +++ b/force-app/main/default/aura/MixChart/MixChartController.js @@ -0,0 +1,68 @@ +({ + scriptsLoaded : function(component) { + + var data = { + labels: ["Womens", "Mens", "Kids", "Gear", "Electronics"], + datasets: [ + { + data: [0, 0, 0, 0, 0, 1], + backgroundColor: [ + "rgba(126,139,228,.8)", + "rgba(84,105,141,.8)", + "rgba(254,143,96,.8)", + "rgba(125,195,125,.8)", + "rgba(52,190,205,.8)", + "#E0E5EE" + ], + hoverBackgroundColor: [ + "rgba(126,139,228,.8)", + "rgba(84,105,141,.8)", + "rgba(254,143,96,.8)", + "rgba(125,195,125,.8)", + "rgba(52,190,205,.8)", + "#E0E5EE" + ] + } + ] + }; + + var ctx = component.find("chart").getElement(); + component.chart = new Chart(ctx,{ + type: 'doughnut', + data: data, + options: { + responsive: true, + maintainAspectRatio: false, + cutoutPercentage: 60, + legend: { + position: "right", + display: false + } + } + + }); + + }, + + mixItemsChangeHandler: function(component) { + if (component.chart && component.chart.data && component.chart.data.datasets[0]) { + var mixItems = component.get("v.mixItems"); + if (mixItems && Array.isArray(mixItems)) { + var map = {}; + mixItems.forEach(function(mixItem) { + map[mixItem.Merchandise__r.Category__c] = (map[mixItem.Merchandise__r.Category__c] || 0) + (mixItem.Qty__c * mixItem.Merchandise__r.Price__c); + }); + var data = [ + map.Womens || 0, + map.Mens || 0, + map.Kids || 0, + map.Gear || 0, + map.Electronics || 0 + ]; + component.chart.data.datasets[0].data = data; + component.chart.update(); + } + } + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/MixItemEvent/MixItemEvent.evt b/force-app/main/default/aura/MixItemEvent/MixItemEvent.evt new file mode 100644 index 0000000..767ce58 --- /dev/null +++ b/force-app/main/default/aura/MixItemEvent/MixItemEvent.evt @@ -0,0 +1,3 @@ + + + diff --git a/force-app/main/default/aura/MixItemEvent/MixItemEvent.evt-meta.xml b/force-app/main/default/aura/MixItemEvent/MixItemEvent.evt-meta.xml new file mode 100644 index 0000000..0fb400c --- /dev/null +++ b/force-app/main/default/aura/MixItemEvent/MixItemEvent.evt-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Event Bundle + diff --git a/force-app/main/default/aura/MixItemTile/MixItemTile.cmp b/force-app/main/default/aura/MixItemTile/MixItemTile.cmp new file mode 100755 index 0000000..c723d6f --- /dev/null +++ b/force-app/main/default/aura/MixItemTile/MixItemTile.cmp @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + {#v.mixItem.Merchandise__r.Name} +
MSRP:
+
Qty: + + +
+
+
+ +
\ No newline at end of file diff --git a/force-app/main/default/aura/MixItemTile/MixItemTile.cmp-meta.xml b/force-app/main/default/aura/MixItemTile/MixItemTile.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/MixItemTile/MixItemTile.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/MixItemTile/MixItemTile.css b/force-app/main/default/aura/MixItemTile/MixItemTile.css new file mode 100755 index 0000000..b0bd67d --- /dev/null +++ b/force-app/main/default/aura/MixItemTile/MixItemTile.css @@ -0,0 +1,55 @@ +.THIS .slds-input { + width: 60px; + padding: 6px; + height:20px; + line-height:18px; + margin-top: 2px; +} + +.THIS a { + color: inherit; +} + +.THIS img.product { + max-height: 75px; + max-width: 75px; +} + +.THIS label { + display: none; +} + +.THIS .price, +.THIS .title { + font-weight: bold; +} + +.THIS .price { + color: #FF6600; +} + +.THIS .slds-form-element { + display: inline-block; + margin: 0 4px; +} + +.THIS { + border: solid 1px transparent; + border-radius: 4px; +} + +.THIS:hover { + border-color: rgba(18,127,178,.5); + /* + box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); + transition: all 0.3s cubic-bezier(.25,.8,.25,1); + */ +} + +.THIS .toggle { + display: none; +} + +.THIS:hover .toggle { + display: inline; +} diff --git a/force-app/main/default/aura/MixItemTile/MixItemTileController.js b/force-app/main/default/aura/MixItemTile/MixItemTileController.js new file mode 100755 index 0000000..1eaeaa5 --- /dev/null +++ b/force-app/main/default/aura/MixItemTile/MixItemTileController.js @@ -0,0 +1,28 @@ +({ + titleClickHandler: function(component) { + var navEvt = $A.get("e.force:navigateToSObject"); + navEvt.setParams({ + "recordId": component.get("v.mixItem").Merchandise__c, + "slideDevName": "detail" + }); + navEvt.fire(); + }, + + deleteHandler : function(component) { + var deleteEvent = component.getEvent("onDelete"); + deleteEvent.setParam("mixItem", component.get("v.mixItem")); + deleteEvent.fire(); + }, + + qtyChangeHandler: function(component, event) { + var qty = event.getSource().get('v.value'); + var mixItem = component.get("v.mixItem"); + if (qty !== mixItem.Qty__c) { + mixItem.Qty__c = parseInt(qty, 10); + var changeEvent = component.getEvent("onChange"); + changeEvent.setParam("mixItem", mixItem); + changeEvent.fire(); + } + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/MixPath/MixPath.cmp b/force-app/main/default/aura/MixPath/MixPath.cmp new file mode 100755 index 0000000..f8111ab --- /dev/null +++ b/force-app/main/default/aura/MixPath/MixPath.cmp @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MixPath/MixPath.cmp-meta.xml b/force-app/main/default/aura/MixPath/MixPath.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/MixPath/MixPath.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/MixPath/MixPath.css b/force-app/main/default/aura/MixPath/MixPath.css new file mode 100755 index 0000000..57b6924 --- /dev/null +++ b/force-app/main/default/aura/MixPath/MixPath.css @@ -0,0 +1,7 @@ +.THIS { + margin: 0 28px; +} + +.THIS svg { + fill: #FFFFFF; +} \ No newline at end of file diff --git a/force-app/main/default/aura/MixPath/MixPath.design b/force-app/main/default/aura/MixPath/MixPath.design new file mode 100755 index 0000000..875d7f2 --- /dev/null +++ b/force-app/main/default/aura/MixPath/MixPath.design @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MixPath/MixPath.svg b/force-app/main/default/aura/MixPath/MixPath.svg new file mode 100755 index 0000000..1f3f5b0 --- /dev/null +++ b/force-app/main/default/aura/MixPath/MixPath.svg @@ -0,0 +1,11 @@ + + + path + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/MixPath/MixPathController.js b/force-app/main/default/aura/MixPath/MixPathController.js new file mode 100755 index 0000000..45ab838 --- /dev/null +++ b/force-app/main/default/aura/MixPath/MixPathController.js @@ -0,0 +1,20 @@ +({ + onStepChange : function(component, event) { + var mix = component.get("v.record"); + if (mix) { + mix.Status__c = event.getParam("step"); + component.find("mixRecord").saveRecord($A.getCallback(function(saveResult) { + // + })); + } + }, + + onRecordUpdated : function(component, event) { + var changeType = event.getParams().changeType; + if (changeType === "CHANGED") { + var service = component.find("mixRecord"); + service.reloadRecord(); + } + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/Paginator/Paginator.cmp b/force-app/main/default/aura/Paginator/Paginator.cmp new file mode 100755 index 0000000..9ca3fb3 --- /dev/null +++ b/force-app/main/default/aura/Paginator/Paginator.cmp @@ -0,0 +1,25 @@ + + + + + + + + + + +
+
+ + + +
+
{!v.total} {!v.label} • page {!v.page} of {!v.pages}
+
+ + + +
+
+ +
\ No newline at end of file diff --git a/force-app/main/default/aura/Paginator/Paginator.cmp-meta.xml b/force-app/main/default/aura/Paginator/Paginator.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/Paginator/Paginator.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/Paginator/Paginator.css b/force-app/main/default/aura/Paginator/Paginator.css new file mode 100755 index 0000000..aee31f0 --- /dev/null +++ b/force-app/main/default/aura/Paginator/Paginator.css @@ -0,0 +1,27 @@ +.THIS { + margin: 8px; + display: -webkit-flex; + display: flex; + -webkit-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + align-items: center; + justify-content: center; +} + +.THIS .left { + +} + +.THIS .right { + text-align: right; +} + +.THIS .centered { + color: #999999; + font-size: 0.9rem; + text-align: center; + align-self: center; + padding: 0 12px; +} \ No newline at end of file diff --git a/force-app/main/default/aura/Paginator/PaginatorController.js b/force-app/main/default/aura/Paginator/PaginatorController.js new file mode 100755 index 0000000..2397b46 --- /dev/null +++ b/force-app/main/default/aura/Paginator/PaginatorController.js @@ -0,0 +1,11 @@ +({ + previousPage : function(component) { + var paginatorEvent = component.getEvent("previousPage"); + paginatorEvent.fire(); + }, + + nextPage : function(component) { + var paginatorEvent = component.getEvent("nextPage"); + paginatorEvent.fire(); + } +}) \ No newline at end of file diff --git a/force-app/main/default/aura/PaginatorEvent/PaginatorEvent.evt b/force-app/main/default/aura/PaginatorEvent/PaginatorEvent.evt new file mode 100755 index 0000000..42e0969 --- /dev/null +++ b/force-app/main/default/aura/PaginatorEvent/PaginatorEvent.evt @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/force-app/main/default/aura/PaginatorEvent/PaginatorEvent.evt-meta.xml b/force-app/main/default/aura/PaginatorEvent/PaginatorEvent.evt-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/PaginatorEvent/PaginatorEvent.evt-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/Path/Path.cmp b/force-app/main/default/aura/Path/Path.cmp new file mode 100755 index 0000000..a5be7ad --- /dev/null +++ b/force-app/main/default/aura/Path/Path.cmp @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/Path/Path.cmp-meta.xml b/force-app/main/default/aura/Path/Path.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/Path/Path.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/Path/Path.css b/force-app/main/default/aura/Path/Path.css new file mode 100755 index 0000000..3017459 --- /dev/null +++ b/force-app/main/default/aura/Path/Path.css @@ -0,0 +1,3 @@ +.THIS svg { + fill: #FFFFFF; +} \ No newline at end of file diff --git a/force-app/main/default/aura/Path/PathController.js b/force-app/main/default/aura/Path/PathController.js new file mode 100755 index 0000000..a1ba581 --- /dev/null +++ b/force-app/main/default/aura/Path/PathController.js @@ -0,0 +1,16 @@ +({ + calculateStepIndex : function(component) { + var steps = component.get("v.steps"); + var currentStep = component.get("v.currentStep"); + var stepIndex = steps.indexOf(currentStep); + component.set("v.stepIndex", stepIndex); + }, + + onStepClicked : function(component, event) { + var step = event.currentTarget.dataset.step; + component.set("v.currentStep", step); + var stepChangeEvent = component.getEvent("stepChange"); + stepChangeEvent.setParam("step", step); + stepChangeEvent.fire(); + } +}) \ No newline at end of file diff --git a/force-app/main/default/aura/PathStepChange/PathStepChange.evt b/force-app/main/default/aura/PathStepChange/PathStepChange.evt new file mode 100755 index 0000000..22cafc8 --- /dev/null +++ b/force-app/main/default/aura/PathStepChange/PathStepChange.evt @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/force-app/main/default/aura/PathStepChange/PathStepChange.evt-meta.xml b/force-app/main/default/aura/PathStepChange/PathStepChange.evt-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/PathStepChange/PathStepChange.evt-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/Range/Range.cmp b/force-app/main/default/aura/Range/Range.cmp new file mode 100755 index 0000000..71bd66d --- /dev/null +++ b/force-app/main/default/aura/Range/Range.cmp @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + {!v.field} Range: + +
+ + + + \ No newline at end of file diff --git a/force-app/main/default/aura/Range/Range.cmp-meta.xml b/force-app/main/default/aura/Range/Range.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/Range/Range.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/Range/Range.css b/force-app/main/default/aura/Range/Range.css new file mode 100755 index 0000000..de88ecf --- /dev/null +++ b/force-app/main/default/aura/Range/Range.css @@ -0,0 +1,66 @@ +.THIS { + height: 36px; + width: 100%; + position: relative; + /*margin-left: -28px;*/ + margin-top: 46px; +} + +.THIS .label { + position: absolute; + top: 64px; + left: 44px; + right: 0; + text-align: center; + max-width: 350px; +} + +.THIS .slider { + /* + position: absolute; + top: 42px; + left: 44px; + right: 0; + */ + width: 270px; + margin-left: 28px; +} + +.THIS .noUi-connect { + /*background: #0070D2;*/ + /*background: #0070D2;*/ + background: #FF6600; + +} + +.THIS .noUi-tooltip { + font-size: .8125rem; + border: none; + color: #FF6600; + font-weight: bold; +} + +.THIS .noUi-target, +.THIS .noUi-handle { + box-shadow: none !important; +} + +.THIS .noUi-target { + background: #FFFFFF; + /*border: 1px solid rgb(216, 221, 230);*/ + border: 1px solid #FF6600; + border-radius: .25rem; +} +/* +.THIS .noUi-horizontal { + height: 6px; + border: 1px solid #EEE; + border-radius: 0; +} + +.THIS .noUi-horizontal .noUi-handle { + height: 26px; + left: -18px; + top: -11px; +} +*/ \ No newline at end of file diff --git a/force-app/main/default/aura/Range/Range.design b/force-app/main/default/aura/Range/Range.design new file mode 100755 index 0000000..25c5b49 --- /dev/null +++ b/force-app/main/default/aura/Range/Range.design @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/force-app/main/default/aura/Range/Range.svg b/force-app/main/default/aura/Range/Range.svg new file mode 100644 index 0000000..5834c04 --- /dev/null +++ b/force-app/main/default/aura/Range/Range.svg @@ -0,0 +1,17 @@ + + + + Group + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/Range/RangeController.js b/force-app/main/default/aura/Range/RangeController.js new file mode 100755 index 0000000..aee6035 --- /dev/null +++ b/force-app/main/default/aura/Range/RangeController.js @@ -0,0 +1,37 @@ +({ + jsLoaded: function(component, event, helper) { + var min = parseInt(component.get("v.min"), 10); + var max = parseInt(component.get("v.max"), 10); + var step = parseInt(component.get("v.step"), 10); + + var slider = component.find('slider').getElement(); + noUiSlider.create(slider, { + start: [min, max], + connect: true, + tooltips: true, + step: step, + format: { + to: function (value ) { + return '$' + Math.round(value); + }, + from: function ( value ) { + return value; + } + }, + range: { + 'min': min, + 'max': max + } + }); + + slider.noUiSlider.on('change', $A.getCallback(function(range) { + var myEvent = $A.get("e.c:RangeChange"); + myEvent.setParams({ + "filterName": component.get("v.filterName"), + "minValue": range[0].replace('$', ''), + "maxValue": range[1].replace('$', '') + }); + myEvent.fire(); + })); + } +}) \ No newline at end of file diff --git a/force-app/main/default/aura/RangeChange/RangeChange.evt b/force-app/main/default/aura/RangeChange/RangeChange.evt new file mode 100755 index 0000000..e0445fe --- /dev/null +++ b/force-app/main/default/aura/RangeChange/RangeChange.evt @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/RangeChange/RangeChange.evt-meta.xml b/force-app/main/default/aura/RangeChange/RangeChange.evt-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/RangeChange/RangeChange.evt-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/SearchBar/SearchBar.cmp b/force-app/main/default/aura/SearchBar/SearchBar.cmp new file mode 100755 index 0000000..5074b14 --- /dev/null +++ b/force-app/main/default/aura/SearchBar/SearchBar.cmp @@ -0,0 +1,12 @@ + + + + +
+ +
+ +
+
+ +
\ No newline at end of file diff --git a/force-app/main/default/aura/SearchBar/SearchBar.cmp-meta.xml b/force-app/main/default/aura/SearchBar/SearchBar.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/SearchBar/SearchBar.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/SearchBar/SearchBar.css b/force-app/main/default/aura/SearchBar/SearchBar.css new file mode 100755 index 0000000..a5839d4 --- /dev/null +++ b/force-app/main/default/aura/SearchBar/SearchBar.css @@ -0,0 +1,2 @@ +.THIS { +} \ No newline at end of file diff --git a/force-app/main/default/aura/SearchBar/SearchBarController.js b/force-app/main/default/aura/SearchBar/SearchBarController.js new file mode 100755 index 0000000..127f577 --- /dev/null +++ b/force-app/main/default/aura/SearchBar/SearchBarController.js @@ -0,0 +1,19 @@ +({ + keyupHandler : function(component, event) { + var changeEvent = component.getEvent("onchange"); + changeEvent.setParams({ + "value": event.target.value + }); + changeEvent.fire(); + }, + + clearHandler : function(component) { + component.find("searchInput").getElement().value = ""; + var changeEvent = component.getEvent("onchange"); + changeEvent.setParams({ + "value": "" + }); + changeEvent.fire(); + } + +}) \ No newline at end of file diff --git a/force-app/main/default/aura/SubcategorySelector/SubcategorySelector.cmp b/force-app/main/default/aura/SubcategorySelector/SubcategorySelector.cmp new file mode 100755 index 0000000..d87b61d --- /dev/null +++ b/force-app/main/default/aura/SubcategorySelector/SubcategorySelector.cmp @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/SubcategorySelector/SubcategorySelector.cmp-meta.xml b/force-app/main/default/aura/SubcategorySelector/SubcategorySelector.cmp-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/SubcategorySelector/SubcategorySelector.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/ValueChange/ValueChange.evt b/force-app/main/default/aura/ValueChange/ValueChange.evt new file mode 100755 index 0000000..d32f82d --- /dev/null +++ b/force-app/main/default/aura/ValueChange/ValueChange.evt @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/force-app/main/default/aura/ValueChange/ValueChange.evt-meta.xml b/force-app/main/default/aura/ValueChange/ValueChange.evt-meta.xml new file mode 100755 index 0000000..20a77e2 --- /dev/null +++ b/force-app/main/default/aura/ValueChange/ValueChange.evt-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/classes/MerchandiseController.cls b/force-app/main/default/classes/MerchandiseController.cls new file mode 100644 index 0000000..4f0803e --- /dev/null +++ b/force-app/main/default/classes/MerchandiseController.cls @@ -0,0 +1,67 @@ +global with sharing class MerchandiseController { + + @AuraEnabled + public static List getCategories() { + Schema.DescribeFieldResult result = Merchandise__c.Category__c.getDescribe(); + List entries = result.getPicklistValues(); + List values = new list (); + for (Schema.PicklistEntry entry: entries) { + values.add(entry.getValue()); + } + return values; + } + + public class PagedResult { + + @AuraEnabled + public Integer pageSize { get;set; } + + @AuraEnabled + public Integer page { get;set; } + + @AuraEnabled + public Integer total { get;set; } + + @AuraEnabled + public List items { get;set; } + + } + + public class Filter { + + @AuraEnabled + public String searchKey { get;set; } + + @AuraEnabled + public String category { get;set; } + + @AuraEnabled + public Decimal minPrice { get;set; } + + @AuraEnabled + public Decimal maxPrice { get;set; } + + } + + @AuraEnabled + public static PagedResult getMerchandise(String filters, Decimal pageSize, Decimal pageNumber) { + Filter filter = (Filter) JSON.deserializeStrict(filters, MerchandiseController.Filter.class); + Integer pSize = (Integer)pageSize; + String key = '%' + filter.searchKey + '%'; + Integer offset = ((Integer)pageNumber - 1) * pSize; + PagedResult r = new PagedResult(); + r.pageSize = pSize; + r.page = (Integer) pageNumber; + r.total = [SELECT count() FROM Merchandise__c + WHERE name LIKE :key + AND Category__c like : (filter.category == '' ? '%' : filter.category) + AND Price__c >= :filter.minPrice AND Price__c <= :filter.maxPrice]; + r.items = [SELECT id, Name, Description__c, Price__c, Category__c, Picture_URL__c FROM Merchandise__c + WHERE Name LIKE :key + AND Category__c like : (filter.category == '' ? '%' : filter.category) + AND Price__c >= :filter.minPrice AND Price__c <= :filter.maxPrice + LIMIT :pSize OFFSET :offset]; + return r; + } + +} \ No newline at end of file diff --git a/force-app/main/default/classes/MerchandiseController.cls-meta.xml b/force-app/main/default/classes/MerchandiseController.cls-meta.xml new file mode 100644 index 0000000..85da595 --- /dev/null +++ b/force-app/main/default/classes/MerchandiseController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + Active + diff --git a/force-app/main/default/classes/MerchandiseMixController.cls b/force-app/main/default/classes/MerchandiseMixController.cls new file mode 100644 index 0000000..fffa2a3 --- /dev/null +++ b/force-app/main/default/classes/MerchandiseMixController.cls @@ -0,0 +1,34 @@ +global with sharing class MerchandiseMixController { + + @AuraEnabled + public static List getMixItems(Id mixId) { + return [SELECT Id, Merchandise__r.Name, Merchandise__r.Price__c, Merchandise__r.Category__c, Merchandise__r.Picture_URL__c, Qty__c + FROM Mix_Item__c + WHERE Merchandising_Mix__c = :mixId]; + } + + @AuraEnabled + public static Mix_Item__c addMixItem(Id mixId, Id productId, Decimal qty) { + Mix_Item__c item = new Mix_Item__c(); + item.Merchandising_Mix__c = mixId; + item.Merchandise__c = productId; + item.Qty__c = 10; + insert item; + return item; + } + + @AuraEnabled + public static Mix_Item__c updateMixItem(Mix_Item__c mixItem) { + update mixItem; + return mixItem; + } + + @AuraEnabled + public static Mix_Item__c removeMixItem(Id mixItemId) { + Mix_Item__c item = new Mix_Item__c(); + item.Id = mixItemId; + delete item; + return item; + } + +} \ No newline at end of file diff --git a/force-app/main/default/classes/MerchandiseMixController.cls-meta.xml b/force-app/main/default/classes/MerchandiseMixController.cls-meta.xml new file mode 100644 index 0000000..69bf828 --- /dev/null +++ b/force-app/main/default/classes/MerchandiseMixController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 40.0 + Active + diff --git a/force-app/main/default/contentassets/nto_logo.asset b/force-app/main/default/contentassets/nto_logo.asset new file mode 100644 index 0000000..dbd30be Binary files /dev/null and b/force-app/main/default/contentassets/nto_logo.asset differ diff --git a/force-app/main/default/contentassets/nto_logo.asset-meta.xml b/force-app/main/default/contentassets/nto_logo.asset-meta.xml new file mode 100644 index 0000000..444d4f7 --- /dev/null +++ b/force-app/main/default/contentassets/nto_logo.asset-meta.xml @@ -0,0 +1,16 @@ + + + en_US + nto_logo + + + VIEWER + + + + + 1 + nto_logo.png + + + diff --git a/force-app/main/default/flexipages/Merchandise_Record_Page.flexipage-meta.xml b/force-app/main/default/flexipages/Merchandise_Record_Page.flexipage-meta.xml new file mode 100644 index 0000000..01cd555 --- /dev/null +++ b/force-app/main/default/flexipages/Merchandise_Record_Page.flexipage-meta.xml @@ -0,0 +1,85 @@ + + + + + force:highlightsPanel + + Replace + header + Region + + + + force:relatedListContainer + + Replace + relatedTabContent + Facet + + + + force:detailPanel + + Replace + detailTabContent + Facet + + + + + body + relatedTabContent + + + title + Standard.Tab.relatedLists + + flexipage:tab + + + + active + true + + + body + detailTabContent + + + title + Standard.Tab.detail + + flexipage:tab + + Replace + maintabs + Facet + + + + + tabs + maintabs + + flexipage:tabset + + Replace + main + Region + + + + MerchandisePicture + + Replace + sidebar + Region + + Merchandise Record Page + flexipage__default_rec_L + Merchandise__c + + RecordPage + diff --git a/force-app/main/default/flexipages/Merchandising_Mix_Record_Page.flexipage-meta.xml b/force-app/main/default/flexipages/Merchandising_Mix_Record_Page.flexipage-meta.xml new file mode 100644 index 0000000..2f5807a --- /dev/null +++ b/force-app/main/default/flexipages/Merchandising_Mix_Record_Page.flexipage-meta.xml @@ -0,0 +1,82 @@ + + + + + + collapsed + false + + + numVisibleActions + 3 + + force:highlightsPanel + + + + pathName + Merchandising Mix + + MixPath + + Replace + header + Region + + + + force:detailPanel + + + + showChart + true + + MerchandiseMix + + Replace + main + Region + + + + + showCategory + true + + + showSearch + true + + + showSubcategory + false + + MerchandiseFilter + + + + filterName + MSRP + + Range + + + + pageSize + 8 + + MerchandiseList + + Replace + sidebar + Region + + Merchandising Mix Record Page + flexipage__default_rec_L + Merchandising_Mix__c + + RecordPage + diff --git a/force-app/main/default/flexipages/Northern_Trail_UtilityBar.flexipage-meta.xml b/force-app/main/default/flexipages/Northern_Trail_UtilityBar.flexipage-meta.xml new file mode 100644 index 0000000..5cfae52 --- /dev/null +++ b/force-app/main/default/flexipages/Northern_Trail_UtilityBar.flexipage-meta.xml @@ -0,0 +1,12 @@ + + + + utilityItems + Region + + Northern Trail UtilityBar + + UtilityBar + diff --git a/force-app/main/default/flowDefinitions/Mix_Status_Change.flowDefinition-meta.xml b/force-app/main/default/flowDefinitions/Mix_Status_Change.flowDefinition-meta.xml new file mode 100644 index 0000000..62c41b3 --- /dev/null +++ b/force-app/main/default/flowDefinitions/Mix_Status_Change.flowDefinition-meta.xml @@ -0,0 +1,4 @@ + + + 3 + diff --git a/force-app/main/default/flows/Mix_Status_Change-3.flow-meta.xml b/force-app/main/default/flows/Mix_Status_Change-3.flow-meta.xml new file mode 100644 index 0000000..bf645c4 --- /dev/null +++ b/force-app/main/default/flows/Mix_Status_Change-3.flow-meta.xml @@ -0,0 +1,440 @@ + + + + myVariable_waitStartTimeAssignment + + 0 + 0 + + myVariable_waitStartTimeVariable + Assign + + $Flow.CurrentDateTime + + + + isChangedDecision2_myRule_1_Status_c + + + + isChangedDecision2_myRule_1_Status_c + + 0 + 0 + + isChangedDecision5_myRule_4_Status_c + + default + + isChangedRule_2_myRule_1_Status_c + and + + myVariable_old + IsNull + + false + + + + myVariable_old.Status__c + NotEqualTo + + myVariable_current.Status__c + + + + isChangedDecision5_myRule_4_Status_c + + + + + + isChangedDecision5_myRule_4_Status_c + + 0 + 0 + + myDecision + + default + + isChangedRule_5_myRule_4_Status_c + and + + myVariable_old + IsNull + + false + + + + myVariable_old.Status__c + NotEqualTo + + myVariable_current.Status__c + + + + myDecision + + + + + + + index + + 0.0 + + + myDecision + + 50 + 0 + + myDecision3 + + default + + myRule_1 + and + + + inputDataType + + Boolean + + + + leftHandSideType + + Picklist + + + + operatorDataType + + String + + + + rightHandSideType + + Boolean + + + isChangedRule_2_myRule_1_Status_c + EqualTo + + true + + + + + inputDataType + + Picklist + + + + leftHandSideType + + Picklist + + + + operatorDataType + + String + + + + rightHandSideType + + Picklist + + + myVariable_current.Status__c + EqualTo + + Submitted to Manufacturing + + + + myRule_1_A1 + + + + + + + index + + 1.0 + + + myDecision3 + + 50 + 0 + default + + myRule_4 + and + + + inputDataType + + Boolean + + + + leftHandSideType + + Picklist + + + + operatorDataType + + String + + + + rightHandSideType + + Boolean + + + isChangedRule_5_myRule_4_Status_c + EqualTo + + true + + + + + inputDataType + + Picklist + + + + leftHandSideType + + Picklist + + + + operatorDataType + + String + + + + rightHandSideType + + Picklist + + + myVariable_current.Status__c + EqualTo + + Draft + + + + myRule_4_A1 + + + + + Mix_Status_Change-3_InterviewLabel + + + ObjectType + + Merchandising_Mix__c + + + + ObjectVariable + + myVariable_current + + + + OldObjectVariable + + myVariable_old + + + + TriggerType + + onAllChanges + + + Workflow + + myRule_1_A1 + + 100 + 200 + + + dataType + + String + + + + isRequired + + false + + + + leftHandSideLabel + + Account + + + + rightHandSideType + + Reference + + + Account__c + + myVariable_current.Account__r.Name + + + + + dataType + + String + + + + isRequired + + false + + + + leftHandSideLabel + + Mix Id + + + + rightHandSideType + + Reference + + + Mix_Id__c + + myVariable_current.Id + + + + + dataType + + String + + + + isRequired + + false + + + + leftHandSideLabel + + Mix Name + + + + rightHandSideType + + Reference + + + Mix_Name__c + + myVariable_current.Name + + + Mix_Submitted__e + + + myRule_4_A1 + + 400 + 200 + + + dataType + + String + + + + isRequired + + false + + + + leftHandSideLabel + + Mix Id + + + + rightHandSideType + + Reference + + + Mix_Id__c + + myVariable_current.Id + + + Mix_Unsubmitted__e + + myVariable_waitStartTimeAssignment + + myVariable_current + SObject + false + true + true + Merchandising_Mix__c + + + myVariable_old + SObject + false + true + false + Merchandising_Mix__c + + + myVariable_waitStartTimeVariable + DateTime + false + false + false + + $Flow.CurrentDateTime + + + diff --git a/force-app/main/default/layouts/Merchandise__c-Product Layout.layout-meta.xml b/force-app/main/default/layouts/Merchandise__c-Product Layout.layout-meta.xml new file mode 100644 index 0000000..9d283b0 --- /dev/null +++ b/force-app/main/default/layouts/Merchandise__c-Product Layout.layout-meta.xml @@ -0,0 +1,91 @@ + + + + false + false + true + + + + Required + Name + + + Edit + Category__c + + + + + Edit + Price__c + + + Edit + OwnerId + + + + + + true + true + true + + + + Edit + Description__c + + + Edit + Picture_URL__c + + + + + + false + false + true + + + + Readonly + CreatedById + + + + + Readonly + LastModifiedById + + + + + + true + false + true + + + + + + + + NAME + Mix_Item__c.Merchandise__c + + false + false + false + false + false + + 00h0v000000NVlD + 4 + 0 + Default + + diff --git a/force-app/main/default/layouts/Merchandising_Mix__c-Merchandising Mix Layout.layout-meta.xml b/force-app/main/default/layouts/Merchandising_Mix__c-Merchandising Mix Layout.layout-meta.xml new file mode 100644 index 0000000..3ce8953 --- /dev/null +++ b/force-app/main/default/layouts/Merchandising_Mix__c-Merchandising Mix Layout.layout-meta.xml @@ -0,0 +1,73 @@ + + + Submit + + false + false + true + + + + Required + Account__c + + + Edit + Season__c + + + + + Required + Name + + + Edit + Status__c + + + + + + true + true + true + + + + + + false + false + true + + + + + + + true + false + true + + + + + + + + NAME + Mix_Item__c.Merchandising_Mix__c + + false + false + false + false + false + + 00h0v000000Izp3 + 4 + 0 + Default + + diff --git a/force-app/main/default/layouts/Mix_Item__c-Mix Item Layout.layout-meta.xml b/force-app/main/default/layouts/Mix_Item__c-Mix Item Layout.layout-meta.xml new file mode 100755 index 0000000..c98fbd4 --- /dev/null +++ b/force-app/main/default/layouts/Mix_Item__c-Mix Item Layout.layout-meta.xml @@ -0,0 +1,64 @@ + + + + false + false + true + + + + Readonly + Name + + + Required + Merchandising_Mix__c + + + + Edit + Qty__c + + + + + + + false + false + true + + + + Readonly + CreatedById + + + + + Readonly + LastModifiedById + + + + + + false + false + true + + + + + + false + false + false + false + false + diff --git a/force-app/main/default/objects/Merchandise__c/Merchandise__c.object-meta.xml b/force-app/main/default/objects/Merchandise__c/Merchandise__c.object-meta.xml new file mode 100644 index 0000000..94cdd00 --- /dev/null +++ b/force-app/main/default/objects/Merchandise__c/Merchandise__c.object-meta.xml @@ -0,0 +1,68 @@ + + + + Accept + Default + + + CancelEdit + Default + + + Clone + Default + + + Delete + Default + + + Edit + Default + + + List + Default + + + New + Default + + + SaveEdit + Default + + + Tab + Default + + + View + Action override created by Lightning App Builder during activation. + Merchandise_Record_Page + Large + false + Flexipage + + false + SYSTEM + Deployed + false + true + false + false + false + false + true + true + true + + + + Text + + Merchandise + + ReadWrite + Public + diff --git a/force-app/main/default/objects/Merchandise__c/fields/Category__c.field-meta.xml b/force-app/main/default/objects/Merchandise__c/fields/Category__c.field-meta.xml new file mode 100644 index 0000000..7c8c4df --- /dev/null +++ b/force-app/main/default/objects/Merchandise__c/fields/Category__c.field-meta.xml @@ -0,0 +1,39 @@ + + + Category__c + false + + false + false + Picklist + + + false + + Womens + false + + + + Mens + false + + + + Kids + false + + + + Gear + false + + + + Electronics + false + + + + + diff --git a/force-app/main/default/objects/Merchandise__c/fields/Description__c.field-meta.xml b/force-app/main/default/objects/Merchandise__c/fields/Description__c.field-meta.xml new file mode 100644 index 0000000..4952149 --- /dev/null +++ b/force-app/main/default/objects/Merchandise__c/fields/Description__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Description__c + false + + 2000 + false + LongTextArea + 4 + diff --git a/force-app/main/default/objects/Merchandise__c/fields/Picture_URL__c.field-meta.xml b/force-app/main/default/objects/Merchandise__c/fields/Picture_URL__c.field-meta.xml new file mode 100644 index 0000000..b4b0f82 --- /dev/null +++ b/force-app/main/default/objects/Merchandise__c/fields/Picture_URL__c.field-meta.xml @@ -0,0 +1,9 @@ + + + Picture_URL__c + false + + false + false + Url + diff --git a/force-app/main/default/objects/Merchandise__c/fields/Price__c.field-meta.xml b/force-app/main/default/objects/Merchandise__c/fields/Price__c.field-meta.xml new file mode 100644 index 0000000..6cfb383 --- /dev/null +++ b/force-app/main/default/objects/Merchandise__c/fields/Price__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Price__c + false + + 10 + false + 2 + false + Currency + diff --git a/force-app/main/default/objects/Merchandise__c/listViews/All.listView-meta.xml b/force-app/main/default/objects/Merchandise__c/listViews/All.listView-meta.xml new file mode 100644 index 0000000..d505851 --- /dev/null +++ b/force-app/main/default/objects/Merchandise__c/listViews/All.listView-meta.xml @@ -0,0 +1,6 @@ + + + All + Everything + + diff --git a/force-app/main/default/objects/Merchandising_Mix__c/Merchandising_Mix__c.object-meta.xml b/force-app/main/default/objects/Merchandising_Mix__c/Merchandising_Mix__c.object-meta.xml new file mode 100644 index 0000000..afb3b34 --- /dev/null +++ b/force-app/main/default/objects/Merchandising_Mix__c/Merchandising_Mix__c.object-meta.xml @@ -0,0 +1,68 @@ + + + + Accept + Default + + + CancelEdit + Default + + + Clone + Default + + + Delete + Default + + + Edit + Default + + + List + Default + + + New + Default + + + SaveEdit + Default + + + Tab + Default + + + View + Action override created by Lightning App Builder during activation. + Merchandising_Mix_Record_Page + Large + false + Flexipage + + false + SYSTEM + Deployed + false + true + false + false + false + false + true + true + true + + + + Text + + Merchandise Mixes + + ControlledByParent + Public + diff --git a/force-app/main/default/objects/Merchandising_Mix__c/fields/Account__c.field-meta.xml b/force-app/main/default/objects/Merchandising_Mix__c/fields/Account__c.field-meta.xml new file mode 100644 index 0000000..735a217 --- /dev/null +++ b/force-app/main/default/objects/Merchandising_Mix__c/fields/Account__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Account__c + false + + Account + Merchandising_Mixes + 0 + false + false + MasterDetail + false + diff --git a/force-app/main/default/objects/Merchandising_Mix__c/fields/Confirmation_Number__c.field-meta.xml b/force-app/main/default/objects/Merchandising_Mix__c/fields/Confirmation_Number__c.field-meta.xml new file mode 100644 index 0000000..da40534 --- /dev/null +++ b/force-app/main/default/objects/Merchandising_Mix__c/fields/Confirmation_Number__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Confirmation_Number__c + false + + 20 + false + false + Text + false + diff --git a/force-app/main/default/objects/Merchandising_Mix__c/fields/Season__c.field-meta.xml b/force-app/main/default/objects/Merchandising_Mix__c/fields/Season__c.field-meta.xml new file mode 100644 index 0000000..c6935ff --- /dev/null +++ b/force-app/main/default/objects/Merchandising_Mix__c/fields/Season__c.field-meta.xml @@ -0,0 +1,35 @@ + + + Season__c + false + + false + false + Picklist + + true + + false + + Winter 2018 + true + + + + Spring 2018 + false + + + + Summer 2018 + false + + + + Fall 2018 + false + + + + + diff --git a/force-app/main/default/objects/Merchandising_Mix__c/fields/Status__c.field-meta.xml b/force-app/main/default/objects/Merchandising_Mix__c/fields/Status__c.field-meta.xml new file mode 100644 index 0000000..e958713 --- /dev/null +++ b/force-app/main/default/objects/Merchandising_Mix__c/fields/Status__c.field-meta.xml @@ -0,0 +1,35 @@ + + + Status__c + false + + false + false + Picklist + + true + + false + + Draft + true + + + + Submitted to Manufacturing + false + + + + Approved by Manufacturing + false + + + + Ordered + false + + + + + diff --git a/force-app/main/default/objects/Merchandising_Mix__c/listViews/All.listView-meta.xml b/force-app/main/default/objects/Merchandising_Mix__c/listViews/All.listView-meta.xml new file mode 100644 index 0000000..d505851 --- /dev/null +++ b/force-app/main/default/objects/Merchandising_Mix__c/listViews/All.listView-meta.xml @@ -0,0 +1,6 @@ + + + All + Everything + + diff --git a/force-app/main/default/objects/Mix_Approved__e/Mix_Approved__e.object-meta.xml b/force-app/main/default/objects/Mix_Approved__e/Mix_Approved__e.object-meta.xml new file mode 100644 index 0000000..c8d5446 --- /dev/null +++ b/force-app/main/default/objects/Mix_Approved__e/Mix_Approved__e.object-meta.xml @@ -0,0 +1,6 @@ + + + Deployed + + Mixes Approved + diff --git a/force-app/main/default/objects/Mix_Approved__e/fields/Confirmation_Number__c.field-meta.xml b/force-app/main/default/objects/Mix_Approved__e/fields/Confirmation_Number__c.field-meta.xml new file mode 100644 index 0000000..d6ade68 --- /dev/null +++ b/force-app/main/default/objects/Mix_Approved__e/fields/Confirmation_Number__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Confirmation_Number__c + false + false + false + false + + 20 + false + Text + false + diff --git a/force-app/main/default/objects/Mix_Approved__e/fields/Mix_Id__c.field-meta.xml b/force-app/main/default/objects/Mix_Approved__e/fields/Mix_Id__c.field-meta.xml new file mode 100644 index 0000000..9a44255 --- /dev/null +++ b/force-app/main/default/objects/Mix_Approved__e/fields/Mix_Id__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Mix_Id__c + false + false + false + false + + 18 + false + Text + false + diff --git a/force-app/main/default/objects/Mix_Item__c/Mix_Item__c.object-meta.xml b/force-app/main/default/objects/Mix_Item__c/Mix_Item__c.object-meta.xml new file mode 100644 index 0000000..f1e07b5 --- /dev/null +++ b/force-app/main/default/objects/Mix_Item__c/Mix_Item__c.object-meta.xml @@ -0,0 +1,65 @@ + + + + Accept + Default + + + CancelEdit + Default + + + Clone + Default + + + Delete + Default + + + Edit + Default + + + List + Default + + + New + Default + + + SaveEdit + Default + + + Tab + Default + + + View + Default + + false + SYSTEM + Deployed + false + true + false + false + false + false + false + true + true + + + MI-{0000000} + + AutoNumber + + Mix Items + + ControlledByParent + Public + diff --git a/force-app/main/default/objects/Mix_Item__c/fields/Merchandise__c.field-meta.xml b/force-app/main/default/objects/Mix_Item__c/fields/Merchandise__c.field-meta.xml new file mode 100644 index 0000000..8b12af1 --- /dev/null +++ b/force-app/main/default/objects/Mix_Item__c/fields/Merchandise__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Merchandise__c + false + + Merchandise__c + Mix Items + Mix_Items + 1 + false + false + MasterDetail + false + diff --git a/force-app/main/default/objects/Mix_Item__c/fields/Merchandising_Mix__c.field-meta.xml b/force-app/main/default/objects/Mix_Item__c/fields/Merchandising_Mix__c.field-meta.xml new file mode 100644 index 0000000..0dec44f --- /dev/null +++ b/force-app/main/default/objects/Mix_Item__c/fields/Merchandising_Mix__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Merchandising_Mix__c + false + + Merchandising_Mix__c + Mix Items + Mix_Items + 0 + false + false + MasterDetail + false + diff --git a/force-app/main/default/objects/Mix_Item__c/fields/Qty__c.field-meta.xml b/force-app/main/default/objects/Mix_Item__c/fields/Qty__c.field-meta.xml new file mode 100644 index 0000000..7d902da --- /dev/null +++ b/force-app/main/default/objects/Mix_Item__c/fields/Qty__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Qty__c + false + + 6 + false + 0 + false + Number + false + diff --git a/force-app/main/default/objects/Mix_Submitted__e/Mix_Submitted__e.object-meta.xml b/force-app/main/default/objects/Mix_Submitted__e/Mix_Submitted__e.object-meta.xml new file mode 100644 index 0000000..16823c0 --- /dev/null +++ b/force-app/main/default/objects/Mix_Submitted__e/Mix_Submitted__e.object-meta.xml @@ -0,0 +1,6 @@ + + + Deployed + + Mixes Submitted + diff --git a/force-app/main/default/objects/Mix_Submitted__e/fields/Account__c.field-meta.xml b/force-app/main/default/objects/Mix_Submitted__e/fields/Account__c.field-meta.xml new file mode 100644 index 0000000..7c18190 --- /dev/null +++ b/force-app/main/default/objects/Mix_Submitted__e/fields/Account__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Account__c + false + false + false + false + + 100 + false + Text + false + diff --git a/force-app/main/default/objects/Mix_Submitted__e/fields/Mix_Id__c.field-meta.xml b/force-app/main/default/objects/Mix_Submitted__e/fields/Mix_Id__c.field-meta.xml new file mode 100644 index 0000000..9a44255 --- /dev/null +++ b/force-app/main/default/objects/Mix_Submitted__e/fields/Mix_Id__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Mix_Id__c + false + false + false + false + + 18 + false + Text + false + diff --git a/force-app/main/default/objects/Mix_Submitted__e/fields/Mix_Name__c.field-meta.xml b/force-app/main/default/objects/Mix_Submitted__e/fields/Mix_Name__c.field-meta.xml new file mode 100644 index 0000000..7934f89 --- /dev/null +++ b/force-app/main/default/objects/Mix_Submitted__e/fields/Mix_Name__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Mix_Name__c + false + false + false + false + + 100 + false + Text + false + diff --git a/force-app/main/default/objects/Mix_Unsubmitted__e/Mix_Unsubmitted__e.object-meta.xml b/force-app/main/default/objects/Mix_Unsubmitted__e/Mix_Unsubmitted__e.object-meta.xml new file mode 100644 index 0000000..bdc9ee3 --- /dev/null +++ b/force-app/main/default/objects/Mix_Unsubmitted__e/Mix_Unsubmitted__e.object-meta.xml @@ -0,0 +1,6 @@ + + + Deployed + + Mixes Unsubmitted + diff --git a/force-app/main/default/objects/Mix_Unsubmitted__e/fields/Mix_Id__c.field-meta.xml b/force-app/main/default/objects/Mix_Unsubmitted__e/fields/Mix_Id__c.field-meta.xml new file mode 100644 index 0000000..9a44255 --- /dev/null +++ b/force-app/main/default/objects/Mix_Unsubmitted__e/fields/Mix_Id__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Mix_Id__c + false + false + false + false + + 18 + false + Text + false + diff --git a/force-app/main/default/permissionsets/NTO.permissionset-meta.xml b/force-app/main/default/permissionsets/NTO.permissionset-meta.xml new file mode 100644 index 0000000..208f724 --- /dev/null +++ b/force-app/main/default/permissionsets/NTO.permissionset-meta.xml @@ -0,0 +1,97 @@ + + + + Northern_Trail + true + + + true + Merchandise__c.Category__c + true + + + true + Merchandise__c.Description__c + true + + + true + Merchandise__c.Picture_URL__c + true + + + true + Merchandise__c.Price__c + true + + + true + Merchandising_Mix__c.Confirmation_Number__c + true + + + true + Merchandising_Mix__c.Season__c + true + + + true + Merchandising_Mix__c.Status__c + true + + + true + Mix_Item__c.Qty__c + true + + false + + + false + false + false + true + false + Account + true + + + true + true + true + true + true + Merchandise__c + true + + + true + true + true + true + true + Merchandising_Mix__c + true + + + true + true + true + true + true + Mix_Item__c + true + + + Merchandise__c + Visible + + + Merchandising_Mix__c + Visible + + + true + ApiEnabled + + diff --git a/force-app/main/default/profiles/Admin.profile-meta.xml b/force-app/main/default/profiles/Admin.profile-meta.xml new file mode 100644 index 0000000..5a03fb5 --- /dev/null +++ b/force-app/main/default/profiles/Admin.profile-meta.xml @@ -0,0 +1,553 @@ + + + false + + 255.255.255.255 + 0.0.0.0 + + Salesforce + + true + ActivateContract + + + true + ActivateOrder + + + true + AllowUniversalSearch + + + true + AllowViewKnowledge + + + true + ApiEnabled + + + true + AssignPermissionSets + + + true + AssignTopics + + + true + AuthorApex + + + true + BulkMacrosAllowed + + + true + CanInsertFeedSystemFields + + + true + CanUseNewDashboardBuilder + + + true + ChatterEditOwnPost + + + true + ChatterEditOwnRecordPost + + + true + ChatterFileLink + + + true + ChatterInternalUser + + + true + ChatterInviteExternalUsers + + + true + ChatterOwnGroups + + + true + ConnectOrgToEnvironmentHub + + + true + ContentAdministrator + + + true + ConvertLeads + + + true + CreateCustomizeDashboards + + + true + CreateCustomizeFilters + + + true + CreateCustomizeReports + + + true + CreateDashboardFolders + + + true + CreateReportFolders + + + true + CreateTopics + + + true + CreateWorkBadgeDefinition + + + true + CreateWorkspaces + + + true + CustomizeApplication + + + true + DelegatedTwoFactor + + + true + DeleteActivatedContract + + + true + DeleteTopics + + + true + DistributeFromPersWksp + + + true + EditActivatedOrders + + + true + EditBillingInfo + + + true + EditBrandTemplates + + + true + EditCaseComments + + + true + EditEvent + + + true + EditHtmlTemplates + + + true + EditKnowledge + + + true + EditMyDashboards + + + true + EditMyReports + + + true + EditOppLineItemUnitPrice + + + true + EditPublicDocuments + + + true + EditPublicFilters + + + true + EditPublicTemplates + + + true + EditReadonlyFields + + + true + EditTask + + + true + EditTopics + + + true + EmailMass + + + true + EmailSingle + + + true + EnableCommunityAppLauncher + + + true + EnableNotifications + + + true + ExportReport + + + true + FieldServiceAccess + + + true + ImportCustomObjects + + + true + ImportLeads + + + true + ImportPersonal + + + true + InstallPackaging + + + true + LightningConsoleAllowedForUser + + + true + LightningExperienceUser + + + true + ManageAnalyticSnapshots + + + true + ManageAuthProviders + + + true + ManageBusinessHourHolidays + + + true + ManageCallCenters + + + true + ManageCases + + + true + ManageCategories + + + true + ManageCertificates + + + true + ManageContentPermissions + + + true + ManageContentProperties + + + true + ManageContentTypes + + + true + ManageCustomPermissions + + + true + ManageCustomReportTypes + + + true + ManageDashbdsInPubFolders + + + true + ManageDataCategories + + + true + ManageDataIntegrations + + + true + ManageDynamicDashboards + + + true + ManageEmailClientConfig + + + true + ManageExchangeConfig + + + true + ManageHealthCheck + + + true + ManageInteraction + + + true + ManageInternalUsers + + + true + ManageIpAddresses + + + true + ManageKnowledge + + + true + ManageKnowledgeImportExport + + + true + ManageLeads + + + true + ManageLoginAccessPolicies + + + true + ManageMobile + + + true + ManageNetworks + + + true + ManagePackageLicenses + + + true + ManagePasswordPolicies + + + true + ManageProfilesPermissionsets + + + true + ManagePvtRptsAndDashbds + + + true + ManageRemoteAccess + + + true + ManageReportsInPubFolders + + + true + ManageRoles + + + true + ManageSearchPromotionRules + + + true + ManageSharing + + + true + ManageSolutions + + + true + ManageSynonyms + + + true + ManageUnlistedGroups + + + true + ManageUsers + + + true + MassInlineEdit + + + true + MergeTopics + + + true + ModerateChatter + + + true + ModifyAllData + + + true + NewReportBuilder + + + true + ResetPasswords + + + true + RunReports + + + true + ScheduleReports + + + true + SelectFilesFromSalesforce + + + true + SendExternalEmailAvailable + + + true + SendSitRequests + + + true + ShareInternalArticles + + + true + ShowCompanyNameAsUserBadge + + + true + SolutionImport + + + true + SubmitMacrosAllowed + + + true + SubscribeReportToOtherUsers + + + true + SubscribeReportsRunAsUser + + + true + SubscribeToLightningReports + + + true + TransferAnyCase + + + true + TransferAnyEntity + + + true + TransferAnyLead + + + true + UseTeamReassignWizards + + + true + ViewAllData + + + true + ViewAllUsers + + + true + ViewDataAssessment + + + true + ViewDataCategories + + + true + ViewEventLogFiles + + + true + ViewHealthCheck + + + true + ViewHelpLink + + + true + ViewMyTeamsDashboards + + + true + ViewPublicDashboards + + + true + ViewPublicReports + + + true + ViewSetup + + + true + WorkCalibrationUser + + diff --git a/force-app/main/default/staticresources/DataCache.resource b/force-app/main/default/staticresources/DataCache.resource new file mode 100755 index 0000000..c50007b --- /dev/null +++ b/force-app/main/default/staticresources/DataCache.resource @@ -0,0 +1,15 @@ +window.DataCache = (function() { + + var cache = {}; + + return { + setData: function(name, data) { + cache[name] = data; + }, + + getData: function(name) { + return cache[name]; + } + }; + +}()); \ No newline at end of file diff --git a/force-app/main/default/staticresources/DataCache.resource-meta.xml b/force-app/main/default/staticresources/DataCache.resource-meta.xml new file mode 100755 index 0000000..6adb110 --- /dev/null +++ b/force-app/main/default/staticresources/DataCache.resource-meta.xml @@ -0,0 +1,5 @@ + + + Private + text/javascript + diff --git a/force-app/main/default/staticresources/chartjs.resource b/force-app/main/default/staticresources/chartjs.resource new file mode 100755 index 0000000..4b392d8 --- /dev/null +++ b/force-app/main/default/staticresources/chartjs.resource @@ -0,0 +1,10635 @@ +/*! + * Chart.js + * http://chartjs.org/ + * Version: 2.3.0 + * + * Copyright 2016 Nick Downie + * Released under the MIT license + * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md + */ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o lum2) { + return (lum1 + 0.05) / (lum2 + 0.05); + } + return (lum2 + 0.05) / (lum1 + 0.05); + }, + + level: function (color2) { + var contrastRatio = this.contrast(color2); + if (contrastRatio >= 7.1) { + return 'AAA'; + } + + return (contrastRatio >= 4.5) ? 'AA' : ''; + }, + + dark: function () { + // YIQ equation from http://24ways.org/2010/calculating-color-contrast + var rgb = this.values.rgb; + var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000; + return yiq < 128; + }, + + light: function () { + return !this.dark(); + }, + + negate: function () { + var rgb = []; + for (var i = 0; i < 3; i++) { + rgb[i] = 255 - this.values.rgb[i]; + } + this.setValues('rgb', rgb); + return this; + }, + + lighten: function (ratio) { + var hsl = this.values.hsl; + hsl[2] += hsl[2] * ratio; + this.setValues('hsl', hsl); + return this; + }, + + darken: function (ratio) { + var hsl = this.values.hsl; + hsl[2] -= hsl[2] * ratio; + this.setValues('hsl', hsl); + return this; + }, + + saturate: function (ratio) { + var hsl = this.values.hsl; + hsl[1] += hsl[1] * ratio; + this.setValues('hsl', hsl); + return this; + }, + + desaturate: function (ratio) { + var hsl = this.values.hsl; + hsl[1] -= hsl[1] * ratio; + this.setValues('hsl', hsl); + return this; + }, + + whiten: function (ratio) { + var hwb = this.values.hwb; + hwb[1] += hwb[1] * ratio; + this.setValues('hwb', hwb); + return this; + }, + + blacken: function (ratio) { + var hwb = this.values.hwb; + hwb[2] += hwb[2] * ratio; + this.setValues('hwb', hwb); + return this; + }, + + greyscale: function () { + var rgb = this.values.rgb; + // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale + var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11; + this.setValues('rgb', [val, val, val]); + return this; + }, + + clearer: function (ratio) { + var alpha = this.values.alpha; + this.setValues('alpha', alpha - (alpha * ratio)); + return this; + }, + + opaquer: function (ratio) { + var alpha = this.values.alpha; + this.setValues('alpha', alpha + (alpha * ratio)); + return this; + }, + + rotate: function (degrees) { + var hsl = this.values.hsl; + var hue = (hsl[0] + degrees) % 360; + hsl[0] = hue < 0 ? 360 + hue : hue; + this.setValues('hsl', hsl); + return this; + }, + + /** + * Ported from sass implementation in C + * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209 + */ + mix: function (mixinColor, weight) { + var color1 = this; + var color2 = mixinColor; + var p = weight === undefined ? 0.5 : weight; + + var w = 2 * p - 1; + var a = color1.alpha() - color2.alpha(); + + var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + var w2 = 1 - w1; + + return this + .rgb( + w1 * color1.red() + w2 * color2.red(), + w1 * color1.green() + w2 * color2.green(), + w1 * color1.blue() + w2 * color2.blue() + ) + .alpha(color1.alpha() * p + color2.alpha() * (1 - p)); + }, + + toJSON: function () { + return this.rgb(); + }, + + clone: function () { + // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify, + // making the final build way to big to embed in Chart.js. So let's do it manually, + // assuming that values to clone are 1 dimension arrays containing only numbers, + // except 'alpha' which is a number. + var result = new Color(); + var source = this.values; + var target = result.values; + var value, type; + + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + value = source[prop]; + type = ({}).toString.call(value); + if (type === '[object Array]') { + target[prop] = value.slice(0); + } else if (type === '[object Number]') { + target[prop] = value; + } else { + console.error('unexpected color value:', value); + } + } + } + + return result; + } +}; + +Color.prototype.spaces = { + rgb: ['red', 'green', 'blue'], + hsl: ['hue', 'saturation', 'lightness'], + hsv: ['hue', 'saturation', 'value'], + hwb: ['hue', 'whiteness', 'blackness'], + cmyk: ['cyan', 'magenta', 'yellow', 'black'] +}; + +Color.prototype.maxes = { + rgb: [255, 255, 255], + hsl: [360, 100, 100], + hsv: [360, 100, 100], + hwb: [360, 100, 100], + cmyk: [100, 100, 100, 100] +}; + +Color.prototype.getValues = function (space) { + var values = this.values; + var vals = {}; + + for (var i = 0; i < space.length; i++) { + vals[space.charAt(i)] = values[space][i]; + } + + if (values.alpha !== 1) { + vals.a = values.alpha; + } + + // {r: 255, g: 255, b: 255, a: 0.4} + return vals; +}; + +Color.prototype.setValues = function (space, vals) { + var values = this.values; + var spaces = this.spaces; + var maxes = this.maxes; + var alpha = 1; + var i; + + if (space === 'alpha') { + alpha = vals; + } else if (vals.length) { + // [10, 10, 10] + values[space] = vals.slice(0, space.length); + alpha = vals[space.length]; + } else if (vals[space.charAt(0)] !== undefined) { + // {r: 10, g: 10, b: 10} + for (i = 0; i < space.length; i++) { + values[space][i] = vals[space.charAt(i)]; + } + + alpha = vals.a; + } else if (vals[spaces[space][0]] !== undefined) { + // {red: 10, green: 10, blue: 10} + var chans = spaces[space]; + + for (i = 0; i < space.length; i++) { + values[space][i] = vals[chans[i]]; + } + + alpha = vals.alpha; + } + + values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha))); + + if (space === 'alpha') { + return false; + } + + var capped; + + // cap values of the space prior converting all values + for (i = 0; i < space.length; i++) { + capped = Math.max(0, Math.min(maxes[space][i], values[space][i])); + values[space][i] = Math.round(capped); + } + + // convert to all the other color spaces + for (var sname in spaces) { + if (sname !== space) { + values[sname] = convert[space][sname](values[space]); + } + } + + return true; +}; + +Color.prototype.setSpace = function (space, args) { + var vals = args[0]; + + if (vals === undefined) { + // color.rgb() + return this.getValues(space); + } + + // color.rgb(10, 10, 10) + if (typeof vals === 'number') { + vals = Array.prototype.slice.call(args); + } + + this.setValues(space, vals); + return this; +}; + +Color.prototype.setChannel = function (space, index, val) { + var svalues = this.values[space]; + if (val === undefined) { + // color.red() + return svalues[index]; + } else if (val === svalues[index]) { + // color.red(color.red()) + return this; + } + + // color.red(100) + svalues[index] = val; + this.setValues(space, svalues); + + return this; +}; + +if (typeof window !== 'undefined') { + window.Color = Color; +} + +module.exports = Color; + +},{"2":2,"5":5}],4:[function(require,module,exports){ +/* MIT license */ + +module.exports = { + rgb2hsl: rgb2hsl, + rgb2hsv: rgb2hsv, + rgb2hwb: rgb2hwb, + rgb2cmyk: rgb2cmyk, + rgb2keyword: rgb2keyword, + rgb2xyz: rgb2xyz, + rgb2lab: rgb2lab, + rgb2lch: rgb2lch, + + hsl2rgb: hsl2rgb, + hsl2hsv: hsl2hsv, + hsl2hwb: hsl2hwb, + hsl2cmyk: hsl2cmyk, + hsl2keyword: hsl2keyword, + + hsv2rgb: hsv2rgb, + hsv2hsl: hsv2hsl, + hsv2hwb: hsv2hwb, + hsv2cmyk: hsv2cmyk, + hsv2keyword: hsv2keyword, + + hwb2rgb: hwb2rgb, + hwb2hsl: hwb2hsl, + hwb2hsv: hwb2hsv, + hwb2cmyk: hwb2cmyk, + hwb2keyword: hwb2keyword, + + cmyk2rgb: cmyk2rgb, + cmyk2hsl: cmyk2hsl, + cmyk2hsv: cmyk2hsv, + cmyk2hwb: cmyk2hwb, + cmyk2keyword: cmyk2keyword, + + keyword2rgb: keyword2rgb, + keyword2hsl: keyword2hsl, + keyword2hsv: keyword2hsv, + keyword2hwb: keyword2hwb, + keyword2cmyk: keyword2cmyk, + keyword2lab: keyword2lab, + keyword2xyz: keyword2xyz, + + xyz2rgb: xyz2rgb, + xyz2lab: xyz2lab, + xyz2lch: xyz2lch, + + lab2xyz: lab2xyz, + lab2rgb: lab2rgb, + lab2lch: lab2lch, + + lch2lab: lch2lab, + lch2xyz: lch2xyz, + lch2rgb: lch2rgb +} + + +function rgb2hsl(rgb) { + var r = rgb[0]/255, + g = rgb[1]/255, + b = rgb[2]/255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s, l; + + if (max == min) + h = 0; + else if (r == max) + h = (g - b) / delta; + else if (g == max) + h = 2 + (b - r) / delta; + else if (b == max) + h = 4 + (r - g)/ delta; + + h = Math.min(h * 60, 360); + + if (h < 0) + h += 360; + + l = (min + max) / 2; + + if (max == min) + s = 0; + else if (l <= 0.5) + s = delta / (max + min); + else + s = delta / (2 - max - min); + + return [h, s * 100, l * 100]; +} + +function rgb2hsv(rgb) { + var r = rgb[0], + g = rgb[1], + b = rgb[2], + min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s, v; + + if (max == 0) + s = 0; + else + s = (delta/max * 1000)/10; + + if (max == min) + h = 0; + else if (r == max) + h = (g - b) / delta; + else if (g == max) + h = 2 + (b - r) / delta; + else if (b == max) + h = 4 + (r - g) / delta; + + h = Math.min(h * 60, 360); + + if (h < 0) + h += 360; + + v = ((max / 255) * 1000) / 10; + + return [h, s, v]; +} + +function rgb2hwb(rgb) { + var r = rgb[0], + g = rgb[1], + b = rgb[2], + h = rgb2hsl(rgb)[0], + w = 1/255 * Math.min(r, Math.min(g, b)), + b = 1 - 1/255 * Math.max(r, Math.max(g, b)); + + return [h, w * 100, b * 100]; +} + +function rgb2cmyk(rgb) { + var r = rgb[0] / 255, + g = rgb[1] / 255, + b = rgb[2] / 255, + c, m, y, k; + + k = Math.min(1 - r, 1 - g, 1 - b); + c = (1 - r - k) / (1 - k) || 0; + m = (1 - g - k) / (1 - k) || 0; + y = (1 - b - k) / (1 - k) || 0; + return [c * 100, m * 100, y * 100, k * 100]; +} + +function rgb2keyword(rgb) { + return reverseKeywords[JSON.stringify(rgb)]; +} + +function rgb2xyz(rgb) { + var r = rgb[0] / 255, + g = rgb[1] / 255, + b = rgb[2] / 255; + + // assume sRGB + r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92); + g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92); + b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92); + + var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); + var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); + var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); + + return [x * 100, y *100, z * 100]; +} + +function rgb2lab(rgb) { + var xyz = rgb2xyz(rgb), + x = xyz[0], + y = xyz[1], + z = xyz[2], + l, a, b; + + x /= 95.047; + y /= 100; + z /= 108.883; + + x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); + y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); + z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); + + l = (116 * y) - 16; + a = 500 * (x - y); + b = 200 * (y - z); + + return [l, a, b]; +} + +function rgb2lch(args) { + return lab2lch(rgb2lab(args)); +} + +function hsl2rgb(hsl) { + var h = hsl[0] / 360, + s = hsl[1] / 100, + l = hsl[2] / 100, + t1, t2, t3, rgb, val; + + if (s == 0) { + val = l * 255; + return [val, val, val]; + } + + if (l < 0.5) + t2 = l * (1 + s); + else + t2 = l + s - l * s; + t1 = 2 * l - t2; + + rgb = [0, 0, 0]; + for (var i = 0; i < 3; i++) { + t3 = h + 1 / 3 * - (i - 1); + t3 < 0 && t3++; + t3 > 1 && t3--; + + if (6 * t3 < 1) + val = t1 + (t2 - t1) * 6 * t3; + else if (2 * t3 < 1) + val = t2; + else if (3 * t3 < 2) + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + else + val = t1; + + rgb[i] = val * 255; + } + + return rgb; +} + +function hsl2hsv(hsl) { + var h = hsl[0], + s = hsl[1] / 100, + l = hsl[2] / 100, + sv, v; + + if(l === 0) { + // no need to do calc on black + // also avoids divide by 0 error + return [0, 0, 0]; + } + + l *= 2; + s *= (l <= 1) ? l : 2 - l; + v = (l + s) / 2; + sv = (2 * s) / (l + s); + return [h, sv * 100, v * 100]; +} + +function hsl2hwb(args) { + return rgb2hwb(hsl2rgb(args)); +} + +function hsl2cmyk(args) { + return rgb2cmyk(hsl2rgb(args)); +} + +function hsl2keyword(args) { + return rgb2keyword(hsl2rgb(args)); +} + + +function hsv2rgb(hsv) { + var h = hsv[0] / 60, + s = hsv[1] / 100, + v = hsv[2] / 100, + hi = Math.floor(h) % 6; + + var f = h - Math.floor(h), + p = 255 * v * (1 - s), + q = 255 * v * (1 - (s * f)), + t = 255 * v * (1 - (s * (1 - f))), + v = 255 * v; + + switch(hi) { + case 0: + return [v, t, p]; + case 1: + return [q, v, p]; + case 2: + return [p, v, t]; + case 3: + return [p, q, v]; + case 4: + return [t, p, v]; + case 5: + return [v, p, q]; + } +} + +function hsv2hsl(hsv) { + var h = hsv[0], + s = hsv[1] / 100, + v = hsv[2] / 100, + sl, l; + + l = (2 - s) * v; + sl = s * v; + sl /= (l <= 1) ? l : 2 - l; + sl = sl || 0; + l /= 2; + return [h, sl * 100, l * 100]; +} + +function hsv2hwb(args) { + return rgb2hwb(hsv2rgb(args)) +} + +function hsv2cmyk(args) { + return rgb2cmyk(hsv2rgb(args)); +} + +function hsv2keyword(args) { + return rgb2keyword(hsv2rgb(args)); +} + +// http://dev.w3.org/csswg/css-color/#hwb-to-rgb +function hwb2rgb(hwb) { + var h = hwb[0] / 360, + wh = hwb[1] / 100, + bl = hwb[2] / 100, + ratio = wh + bl, + i, v, f, n; + + // wh + bl cant be > 1 + if (ratio > 1) { + wh /= ratio; + bl /= ratio; + } + + i = Math.floor(6 * h); + v = 1 - bl; + f = 6 * h - i; + if ((i & 0x01) != 0) { + f = 1 - f; + } + n = wh + f * (v - wh); // linear interpolation + + switch (i) { + default: + case 6: + case 0: r = v; g = n; b = wh; break; + case 1: r = n; g = v; b = wh; break; + case 2: r = wh; g = v; b = n; break; + case 3: r = wh; g = n; b = v; break; + case 4: r = n; g = wh; b = v; break; + case 5: r = v; g = wh; b = n; break; + } + + return [r * 255, g * 255, b * 255]; +} + +function hwb2hsl(args) { + return rgb2hsl(hwb2rgb(args)); +} + +function hwb2hsv(args) { + return rgb2hsv(hwb2rgb(args)); +} + +function hwb2cmyk(args) { + return rgb2cmyk(hwb2rgb(args)); +} + +function hwb2keyword(args) { + return rgb2keyword(hwb2rgb(args)); +} + +function cmyk2rgb(cmyk) { + var c = cmyk[0] / 100, + m = cmyk[1] / 100, + y = cmyk[2] / 100, + k = cmyk[3] / 100, + r, g, b; + + r = 1 - Math.min(1, c * (1 - k) + k); + g = 1 - Math.min(1, m * (1 - k) + k); + b = 1 - Math.min(1, y * (1 - k) + k); + return [r * 255, g * 255, b * 255]; +} + +function cmyk2hsl(args) { + return rgb2hsl(cmyk2rgb(args)); +} + +function cmyk2hsv(args) { + return rgb2hsv(cmyk2rgb(args)); +} + +function cmyk2hwb(args) { + return rgb2hwb(cmyk2rgb(args)); +} + +function cmyk2keyword(args) { + return rgb2keyword(cmyk2rgb(args)); +} + + +function xyz2rgb(xyz) { + var x = xyz[0] / 100, + y = xyz[1] / 100, + z = xyz[2] / 100, + r, g, b; + + r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); + g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); + b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); + + // assume sRGB + r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055) + : r = (r * 12.92); + + g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055) + : g = (g * 12.92); + + b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055) + : b = (b * 12.92); + + r = Math.min(Math.max(0, r), 1); + g = Math.min(Math.max(0, g), 1); + b = Math.min(Math.max(0, b), 1); + + return [r * 255, g * 255, b * 255]; +} + +function xyz2lab(xyz) { + var x = xyz[0], + y = xyz[1], + z = xyz[2], + l, a, b; + + x /= 95.047; + y /= 100; + z /= 108.883; + + x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); + y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); + z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); + + l = (116 * y) - 16; + a = 500 * (x - y); + b = 200 * (y - z); + + return [l, a, b]; +} + +function xyz2lch(args) { + return lab2lch(xyz2lab(args)); +} + +function lab2xyz(lab) { + var l = lab[0], + a = lab[1], + b = lab[2], + x, y, z, y2; + + if (l <= 8) { + y = (l * 100) / 903.3; + y2 = (7.787 * (y / 100)) + (16 / 116); + } else { + y = 100 * Math.pow((l + 16) / 116, 3); + y2 = Math.pow(y / 100, 1/3); + } + + x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3); + + z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3); + + return [x, y, z]; +} + +function lab2lch(lab) { + var l = lab[0], + a = lab[1], + b = lab[2], + hr, h, c; + + hr = Math.atan2(b, a); + h = hr * 360 / 2 / Math.PI; + if (h < 0) { + h += 360; + } + c = Math.sqrt(a * a + b * b); + return [l, c, h]; +} + +function lab2rgb(args) { + return xyz2rgb(lab2xyz(args)); +} + +function lch2lab(lch) { + var l = lch[0], + c = lch[1], + h = lch[2], + a, b, hr; + + hr = h / 360 * 2 * Math.PI; + a = c * Math.cos(hr); + b = c * Math.sin(hr); + return [l, a, b]; +} + +function lch2xyz(args) { + return lab2xyz(lch2lab(args)); +} + +function lch2rgb(args) { + return lab2rgb(lch2lab(args)); +} + +function keyword2rgb(keyword) { + return cssKeywords[keyword]; +} + +function keyword2hsl(args) { + return rgb2hsl(keyword2rgb(args)); +} + +function keyword2hsv(args) { + return rgb2hsv(keyword2rgb(args)); +} + +function keyword2hwb(args) { + return rgb2hwb(keyword2rgb(args)); +} + +function keyword2cmyk(args) { + return rgb2cmyk(keyword2rgb(args)); +} + +function keyword2lab(args) { + return rgb2lab(keyword2rgb(args)); +} + +function keyword2xyz(args) { + return rgb2xyz(keyword2rgb(args)); +} + +var cssKeywords = { + aliceblue: [240,248,255], + antiquewhite: [250,235,215], + aqua: [0,255,255], + aquamarine: [127,255,212], + azure: [240,255,255], + beige: [245,245,220], + bisque: [255,228,196], + black: [0,0,0], + blanchedalmond: [255,235,205], + blue: [0,0,255], + blueviolet: [138,43,226], + brown: [165,42,42], + burlywood: [222,184,135], + cadetblue: [95,158,160], + chartreuse: [127,255,0], + chocolate: [210,105,30], + coral: [255,127,80], + cornflowerblue: [100,149,237], + cornsilk: [255,248,220], + crimson: [220,20,60], + cyan: [0,255,255], + darkblue: [0,0,139], + darkcyan: [0,139,139], + darkgoldenrod: [184,134,11], + darkgray: [169,169,169], + darkgreen: [0,100,0], + darkgrey: [169,169,169], + darkkhaki: [189,183,107], + darkmagenta: [139,0,139], + darkolivegreen: [85,107,47], + darkorange: [255,140,0], + darkorchid: [153,50,204], + darkred: [139,0,0], + darksalmon: [233,150,122], + darkseagreen: [143,188,143], + darkslateblue: [72,61,139], + darkslategray: [47,79,79], + darkslategrey: [47,79,79], + darkturquoise: [0,206,209], + darkviolet: [148,0,211], + deeppink: [255,20,147], + deepskyblue: [0,191,255], + dimgray: [105,105,105], + dimgrey: [105,105,105], + dodgerblue: [30,144,255], + firebrick: [178,34,34], + floralwhite: [255,250,240], + forestgreen: [34,139,34], + fuchsia: [255,0,255], + gainsboro: [220,220,220], + ghostwhite: [248,248,255], + gold: [255,215,0], + goldenrod: [218,165,32], + gray: [128,128,128], + green: [0,128,0], + greenyellow: [173,255,47], + grey: [128,128,128], + honeydew: [240,255,240], + hotpink: [255,105,180], + indianred: [205,92,92], + indigo: [75,0,130], + ivory: [255,255,240], + khaki: [240,230,140], + lavender: [230,230,250], + lavenderblush: [255,240,245], + lawngreen: [124,252,0], + lemonchiffon: [255,250,205], + lightblue: [173,216,230], + lightcoral: [240,128,128], + lightcyan: [224,255,255], + lightgoldenrodyellow: [250,250,210], + lightgray: [211,211,211], + lightgreen: [144,238,144], + lightgrey: [211,211,211], + lightpink: [255,182,193], + lightsalmon: [255,160,122], + lightseagreen: [32,178,170], + lightskyblue: [135,206,250], + lightslategray: [119,136,153], + lightslategrey: [119,136,153], + lightsteelblue: [176,196,222], + lightyellow: [255,255,224], + lime: [0,255,0], + limegreen: [50,205,50], + linen: [250,240,230], + magenta: [255,0,255], + maroon: [128,0,0], + mediumaquamarine: [102,205,170], + mediumblue: [0,0,205], + mediumorchid: [186,85,211], + mediumpurple: [147,112,219], + mediumseagreen: [60,179,113], + mediumslateblue: [123,104,238], + mediumspringgreen: [0,250,154], + mediumturquoise: [72,209,204], + mediumvioletred: [199,21,133], + midnightblue: [25,25,112], + mintcream: [245,255,250], + mistyrose: [255,228,225], + moccasin: [255,228,181], + navajowhite: [255,222,173], + navy: [0,0,128], + oldlace: [253,245,230], + olive: [128,128,0], + olivedrab: [107,142,35], + orange: [255,165,0], + orangered: [255,69,0], + orchid: [218,112,214], + palegoldenrod: [238,232,170], + palegreen: [152,251,152], + paleturquoise: [175,238,238], + palevioletred: [219,112,147], + papayawhip: [255,239,213], + peachpuff: [255,218,185], + peru: [205,133,63], + pink: [255,192,203], + plum: [221,160,221], + powderblue: [176,224,230], + purple: [128,0,128], + rebeccapurple: [102, 51, 153], + red: [255,0,0], + rosybrown: [188,143,143], + royalblue: [65,105,225], + saddlebrown: [139,69,19], + salmon: [250,128,114], + sandybrown: [244,164,96], + seagreen: [46,139,87], + seashell: [255,245,238], + sienna: [160,82,45], + silver: [192,192,192], + skyblue: [135,206,235], + slateblue: [106,90,205], + slategray: [112,128,144], + slategrey: [112,128,144], + snow: [255,250,250], + springgreen: [0,255,127], + steelblue: [70,130,180], + tan: [210,180,140], + teal: [0,128,128], + thistle: [216,191,216], + tomato: [255,99,71], + turquoise: [64,224,208], + violet: [238,130,238], + wheat: [245,222,179], + white: [255,255,255], + whitesmoke: [245,245,245], + yellow: [255,255,0], + yellowgreen: [154,205,50] +}; + +var reverseKeywords = {}; +for (var key in cssKeywords) { + reverseKeywords[JSON.stringify(cssKeywords[key])] = key; +} + +},{}],5:[function(require,module,exports){ +var conversions = require(4); + +var convert = function() { + return new Converter(); +} + +for (var func in conversions) { + // export Raw versions + convert[func + "Raw"] = (function(func) { + // accept array or plain args + return function(arg) { + if (typeof arg == "number") + arg = Array.prototype.slice.call(arguments); + return conversions[func](arg); + } + })(func); + + var pair = /(\w+)2(\w+)/.exec(func), + from = pair[1], + to = pair[2]; + + // export rgb2hsl and ["rgb"]["hsl"] + convert[from] = convert[from] || {}; + + convert[from][to] = convert[func] = (function(func) { + return function(arg) { + if (typeof arg == "number") + arg = Array.prototype.slice.call(arguments); + + var val = conversions[func](arg); + if (typeof val == "string" || val === undefined) + return val; // keyword + + for (var i = 0; i < val.length; i++) + val[i] = Math.round(val[i]); + return val; + } + })(func); +} + + +/* Converter does lazy conversion and caching */ +var Converter = function() { + this.convs = {}; +}; + +/* Either get the values for a space or + set the values for a space, depending on args */ +Converter.prototype.routeSpace = function(space, args) { + var values = args[0]; + if (values === undefined) { + // color.rgb() + return this.getValues(space); + } + // color.rgb(10, 10, 10) + if (typeof values == "number") { + values = Array.prototype.slice.call(args); + } + + return this.setValues(space, values); +}; + +/* Set the values for a space, invalidating cache */ +Converter.prototype.setValues = function(space, values) { + this.space = space; + this.convs = {}; + this.convs[space] = values; + return this; +}; + +/* Get the values for a space. If there's already + a conversion for the space, fetch it, otherwise + compute it */ +Converter.prototype.getValues = function(space) { + var vals = this.convs[space]; + if (!vals) { + var fspace = this.space, + from = this.convs[fspace]; + vals = convert[fspace][space](from); + + this.convs[space] = vals; + } + return vals; +}; + +["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) { + Converter.prototype[space] = function(vals) { + return this.routeSpace(space, arguments); + } +}); + +module.exports = convert; +},{"4":4}],6:[function(require,module,exports){ +module.exports = { + "aliceblue": [240, 248, 255], + "antiquewhite": [250, 235, 215], + "aqua": [0, 255, 255], + "aquamarine": [127, 255, 212], + "azure": [240, 255, 255], + "beige": [245, 245, 220], + "bisque": [255, 228, 196], + "black": [0, 0, 0], + "blanchedalmond": [255, 235, 205], + "blue": [0, 0, 255], + "blueviolet": [138, 43, 226], + "brown": [165, 42, 42], + "burlywood": [222, 184, 135], + "cadetblue": [95, 158, 160], + "chartreuse": [127, 255, 0], + "chocolate": [210, 105, 30], + "coral": [255, 127, 80], + "cornflowerblue": [100, 149, 237], + "cornsilk": [255, 248, 220], + "crimson": [220, 20, 60], + "cyan": [0, 255, 255], + "darkblue": [0, 0, 139], + "darkcyan": [0, 139, 139], + "darkgoldenrod": [184, 134, 11], + "darkgray": [169, 169, 169], + "darkgreen": [0, 100, 0], + "darkgrey": [169, 169, 169], + "darkkhaki": [189, 183, 107], + "darkmagenta": [139, 0, 139], + "darkolivegreen": [85, 107, 47], + "darkorange": [255, 140, 0], + "darkorchid": [153, 50, 204], + "darkred": [139, 0, 0], + "darksalmon": [233, 150, 122], + "darkseagreen": [143, 188, 143], + "darkslateblue": [72, 61, 139], + "darkslategray": [47, 79, 79], + "darkslategrey": [47, 79, 79], + "darkturquoise": [0, 206, 209], + "darkviolet": [148, 0, 211], + "deeppink": [255, 20, 147], + "deepskyblue": [0, 191, 255], + "dimgray": [105, 105, 105], + "dimgrey": [105, 105, 105], + "dodgerblue": [30, 144, 255], + "firebrick": [178, 34, 34], + "floralwhite": [255, 250, 240], + "forestgreen": [34, 139, 34], + "fuchsia": [255, 0, 255], + "gainsboro": [220, 220, 220], + "ghostwhite": [248, 248, 255], + "gold": [255, 215, 0], + "goldenrod": [218, 165, 32], + "gray": [128, 128, 128], + "green": [0, 128, 0], + "greenyellow": [173, 255, 47], + "grey": [128, 128, 128], + "honeydew": [240, 255, 240], + "hotpink": [255, 105, 180], + "indianred": [205, 92, 92], + "indigo": [75, 0, 130], + "ivory": [255, 255, 240], + "khaki": [240, 230, 140], + "lavender": [230, 230, 250], + "lavenderblush": [255, 240, 245], + "lawngreen": [124, 252, 0], + "lemonchiffon": [255, 250, 205], + "lightblue": [173, 216, 230], + "lightcoral": [240, 128, 128], + "lightcyan": [224, 255, 255], + "lightgoldenrodyellow": [250, 250, 210], + "lightgray": [211, 211, 211], + "lightgreen": [144, 238, 144], + "lightgrey": [211, 211, 211], + "lightpink": [255, 182, 193], + "lightsalmon": [255, 160, 122], + "lightseagreen": [32, 178, 170], + "lightskyblue": [135, 206, 250], + "lightslategray": [119, 136, 153], + "lightslategrey": [119, 136, 153], + "lightsteelblue": [176, 196, 222], + "lightyellow": [255, 255, 224], + "lime": [0, 255, 0], + "limegreen": [50, 205, 50], + "linen": [250, 240, 230], + "magenta": [255, 0, 255], + "maroon": [128, 0, 0], + "mediumaquamarine": [102, 205, 170], + "mediumblue": [0, 0, 205], + "mediumorchid": [186, 85, 211], + "mediumpurple": [147, 112, 219], + "mediumseagreen": [60, 179, 113], + "mediumslateblue": [123, 104, 238], + "mediumspringgreen": [0, 250, 154], + "mediumturquoise": [72, 209, 204], + "mediumvioletred": [199, 21, 133], + "midnightblue": [25, 25, 112], + "mintcream": [245, 255, 250], + "mistyrose": [255, 228, 225], + "moccasin": [255, 228, 181], + "navajowhite": [255, 222, 173], + "navy": [0, 0, 128], + "oldlace": [253, 245, 230], + "olive": [128, 128, 0], + "olivedrab": [107, 142, 35], + "orange": [255, 165, 0], + "orangered": [255, 69, 0], + "orchid": [218, 112, 214], + "palegoldenrod": [238, 232, 170], + "palegreen": [152, 251, 152], + "paleturquoise": [175, 238, 238], + "palevioletred": [219, 112, 147], + "papayawhip": [255, 239, 213], + "peachpuff": [255, 218, 185], + "peru": [205, 133, 63], + "pink": [255, 192, 203], + "plum": [221, 160, 221], + "powderblue": [176, 224, 230], + "purple": [128, 0, 128], + "rebeccapurple": [102, 51, 153], + "red": [255, 0, 0], + "rosybrown": [188, 143, 143], + "royalblue": [65, 105, 225], + "saddlebrown": [139, 69, 19], + "salmon": [250, 128, 114], + "sandybrown": [244, 164, 96], + "seagreen": [46, 139, 87], + "seashell": [255, 245, 238], + "sienna": [160, 82, 45], + "silver": [192, 192, 192], + "skyblue": [135, 206, 235], + "slateblue": [106, 90, 205], + "slategray": [112, 128, 144], + "slategrey": [112, 128, 144], + "snow": [255, 250, 250], + "springgreen": [0, 255, 127], + "steelblue": [70, 130, 180], + "tan": [210, 180, 140], + "teal": [0, 128, 128], + "thistle": [216, 191, 216], + "tomato": [255, 99, 71], + "turquoise": [64, 224, 208], + "violet": [238, 130, 238], + "wheat": [245, 222, 179], + "white": [255, 255, 255], + "whitesmoke": [245, 245, 245], + "yellow": [255, 255, 0], + "yellowgreen": [154, 205, 50] +}; +},{}],7:[function(require,module,exports){ +/** + * @namespace Chart + */ +var Chart = require(27)(); + +require(26)(Chart); +require(22)(Chart); +require(25)(Chart); +require(21)(Chart); +require(23)(Chart); +require(24)(Chart); +require(28)(Chart); +require(32)(Chart); +require(30)(Chart); +require(31)(Chart); +require(33)(Chart); +require(29)(Chart); +require(34)(Chart); + +require(35)(Chart); +require(36)(Chart); +require(37)(Chart); +require(38)(Chart); + +require(41)(Chart); +require(39)(Chart); +require(40)(Chart); +require(42)(Chart); +require(43)(Chart); +require(44)(Chart); + +// Controllers must be loaded after elements +// See Chart.core.datasetController.dataElementType +require(15)(Chart); +require(16)(Chart); +require(17)(Chart); +require(18)(Chart); +require(19)(Chart); +require(20)(Chart); + +require(8)(Chart); +require(9)(Chart); +require(10)(Chart); +require(11)(Chart); +require(12)(Chart); +require(13)(Chart); +require(14)(Chart); + +window.Chart = module.exports = Chart; + +},{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"34":34,"35":35,"36":36,"37":37,"38":38,"39":39,"40":40,"41":41,"42":42,"43":43,"44":44,"8":8,"9":9}],8:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Bar = function(context, config) { + config.type = 'bar'; + + return new Chart(context, config); + }; + +}; + +},{}],9:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Bubble = function(context, config) { + config.type = 'bubble'; + return new Chart(context, config); + }; + +}; + +},{}],10:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Doughnut = function(context, config) { + config.type = 'doughnut'; + + return new Chart(context, config); + }; + +}; + +},{}],11:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Line = function(context, config) { + config.type = 'line'; + + return new Chart(context, config); + }; + +}; + +},{}],12:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.PolarArea = function(context, config) { + config.type = 'polarArea'; + + return new Chart(context, config); + }; + +}; + +},{}],13:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Radar = function(context, config) { + config.options = Chart.helpers.configMerge({aspectRatio: 1}, config.options); + config.type = 'radar'; + + return new Chart(context, config); + }; + +}; + +},{}],14:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + var defaultConfig = { + hover: { + mode: 'single' + }, + + scales: { + xAxes: [{ + type: 'linear', // scatter should not use a category axis + position: 'bottom', + id: 'x-axis-1' // need an ID so datasets can reference the scale + }], + yAxes: [{ + type: 'linear', + position: 'left', + id: 'y-axis-1' + }] + }, + + tooltips: { + callbacks: { + title: function() { + // Title doesn't make sense for scatter since we format the data as a point + return ''; + }, + label: function(tooltipItem) { + return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')'; + } + } + } + }; + + // Register the default config for this type + Chart.defaults.scatter = defaultConfig; + + // Scatter charts use line controllers + Chart.controllers.scatter = Chart.controllers.line; + + Chart.Scatter = function(context, config) { + config.type = 'scatter'; + return new Chart(context, config); + }; + +}; + +},{}],15:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.bar = { + hover: { + mode: 'label' + }, + + scales: { + xAxes: [{ + type: 'category', + + // Specific to Bar Controller + categoryPercentage: 0.8, + barPercentage: 0.9, + + // grid line settings + gridLines: { + offsetGridLines: true + } + }], + yAxes: [{ + type: 'linear' + }] + } + }; + + Chart.controllers.bar = Chart.DatasetController.extend({ + + dataElementType: Chart.elements.Rectangle, + + initialize: function(chart, datasetIndex) { + Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex); + + // Use this to indicate that this is a bar dataset. + this.getMeta().bar = true; + }, + + // Get the number of datasets that display bars. We use this to correctly calculate the bar width + getBarCount: function() { + var me = this; + var barCount = 0; + helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) { + var meta = me.chart.getDatasetMeta(datasetIndex); + if (meta.bar && me.chart.isDatasetVisible(datasetIndex)) { + ++barCount; + } + }, me); + return barCount; + }, + + update: function(reset) { + var me = this; + helpers.each(me.getMeta().data, function(rectangle, index) { + me.updateElement(rectangle, index, reset); + }, me); + }, + + updateElement: function(rectangle, index, reset) { + var me = this; + var meta = me.getMeta(); + var xScale = me.getScaleForId(meta.xAxisID); + var yScale = me.getScaleForId(meta.yAxisID); + var scaleBase = yScale.getBasePixel(); + var rectangleElementOptions = me.chart.options.elements.rectangle; + var custom = rectangle.custom || {}; + var dataset = me.getDataset(); + + helpers.extend(rectangle, { + // Utility + _xScale: xScale, + _yScale: yScale, + _datasetIndex: me.index, + _index: index, + + // Desired view properties + _model: { + x: me.calculateBarX(index, me.index), + y: reset ? scaleBase : me.calculateBarY(index, me.index), + + // Tooltip + label: me.chart.data.labels[index], + datasetLabel: dataset.label, + + // Appearance + base: reset ? scaleBase : me.calculateBarBase(me.index, index), + width: me.calculateBarWidth(index), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), + borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped, + borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), + borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) + } + }); + rectangle.pivot(); + }, + + calculateBarBase: function(datasetIndex, index) { + var me = this; + var meta = me.getMeta(); + var yScale = me.getScaleForId(meta.yAxisID); + var base = 0; + + if (yScale.options.stacked) { + var chart = me.chart; + var datasets = chart.data.datasets; + var value = Number(datasets[datasetIndex].data[index]); + + for (var i = 0; i < datasetIndex; i++) { + var currentDs = datasets[i]; + var currentDsMeta = chart.getDatasetMeta(i); + if (currentDsMeta.bar && currentDsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) { + var currentVal = Number(currentDs.data[index]); + base += value < 0 ? Math.min(currentVal, 0) : Math.max(currentVal, 0); + } + } + + return yScale.getPixelForValue(base); + } + + return yScale.getBasePixel(); + }, + + getRuler: function(index) { + var me = this; + var meta = me.getMeta(); + var xScale = me.getScaleForId(meta.xAxisID); + var datasetCount = me.getBarCount(); + + var tickWidth; + + if (xScale.options.type === 'category') { + tickWidth = xScale.getPixelForTick(index + 1) - xScale.getPixelForTick(index); + } else { + // Average width + tickWidth = xScale.width / xScale.ticks.length; + } + var categoryWidth = tickWidth * xScale.options.categoryPercentage; + var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2; + var fullBarWidth = categoryWidth / datasetCount; + + if (xScale.ticks.length !== me.chart.data.labels.length) { + var perc = xScale.ticks.length / me.chart.data.labels.length; + fullBarWidth = fullBarWidth * perc; + } + + var barWidth = fullBarWidth * xScale.options.barPercentage; + var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage); + + return { + datasetCount: datasetCount, + tickWidth: tickWidth, + categoryWidth: categoryWidth, + categorySpacing: categorySpacing, + fullBarWidth: fullBarWidth, + barWidth: barWidth, + barSpacing: barSpacing + }; + }, + + calculateBarWidth: function(index) { + var xScale = this.getScaleForId(this.getMeta().xAxisID); + if (xScale.options.barThickness) { + return xScale.options.barThickness; + } + var ruler = this.getRuler(index); + return xScale.options.stacked ? ruler.categoryWidth : ruler.barWidth; + }, + + // Get bar index from the given dataset index accounting for the fact that not all bars are visible + getBarIndex: function(datasetIndex) { + var barIndex = 0; + var meta, j; + + for (j = 0; j < datasetIndex; ++j) { + meta = this.chart.getDatasetMeta(j); + if (meta.bar && this.chart.isDatasetVisible(j)) { + ++barIndex; + } + } + + return barIndex; + }, + + calculateBarX: function(index, datasetIndex) { + var me = this; + var meta = me.getMeta(); + var xScale = me.getScaleForId(meta.xAxisID); + var barIndex = me.getBarIndex(datasetIndex); + + var ruler = me.getRuler(index); + var leftTick = xScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo); + leftTick -= me.chart.isCombo ? (ruler.tickWidth / 2) : 0; + + if (xScale.options.stacked) { + return leftTick + (ruler.categoryWidth / 2) + ruler.categorySpacing; + } + + return leftTick + + (ruler.barWidth / 2) + + ruler.categorySpacing + + (ruler.barWidth * barIndex) + + (ruler.barSpacing / 2) + + (ruler.barSpacing * barIndex); + }, + + calculateBarY: function(index, datasetIndex) { + var me = this; + var meta = me.getMeta(); + var yScale = me.getScaleForId(meta.yAxisID); + var value = Number(me.getDataset().data[index]); + + if (yScale.options.stacked) { + + var sumPos = 0, + sumNeg = 0; + + for (var i = 0; i < datasetIndex; i++) { + var ds = me.chart.data.datasets[i]; + var dsMeta = me.chart.getDatasetMeta(i); + if (dsMeta.bar && dsMeta.yAxisID === yScale.id && me.chart.isDatasetVisible(i)) { + var stackedVal = Number(ds.data[index]); + if (stackedVal < 0) { + sumNeg += stackedVal || 0; + } else { + sumPos += stackedVal || 0; + } + } + } + + if (value < 0) { + return yScale.getPixelForValue(sumNeg + value); + } + return yScale.getPixelForValue(sumPos + value); + } + + return yScale.getPixelForValue(value); + }, + + draw: function(ease) { + var me = this; + var easingDecimal = ease || 1; + helpers.each(me.getMeta().data, function(rectangle, index) { + var d = me.getDataset().data[index]; + if (d !== null && d !== undefined && !isNaN(d)) { + rectangle.transition(easingDecimal).draw(); + } + }, me); + }, + + setHoverStyle: function(rectangle) { + var dataset = this.chart.data.datasets[rectangle._datasetIndex]; + var index = rectangle._index; + + var custom = rectangle.custom || {}; + var model = rectangle._model; + model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); + model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor)); + model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth); + }, + + removeHoverStyle: function(rectangle) { + var dataset = this.chart.data.datasets[rectangle._datasetIndex]; + var index = rectangle._index; + var custom = rectangle.custom || {}; + var model = rectangle._model; + var rectangleElementOptions = this.chart.options.elements.rectangle; + + model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor); + model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor); + model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth); + } + + }); + + + // including horizontalBar in the bar file, instead of a file of its own + // it extends bar (like pie extends doughnut) + Chart.defaults.horizontalBar = { + hover: { + mode: 'label' + }, + + scales: { + xAxes: [{ + type: 'linear', + position: 'bottom' + }], + yAxes: [{ + position: 'left', + type: 'category', + + // Specific to Horizontal Bar Controller + categoryPercentage: 0.8, + barPercentage: 0.9, + + // grid line settings + gridLines: { + offsetGridLines: true + } + }] + }, + elements: { + rectangle: { + borderSkipped: 'left' + } + }, + tooltips: { + callbacks: { + title: function(tooltipItems, data) { + // Pick first xLabel for now + var title = ''; + + if (tooltipItems.length > 0) { + if (tooltipItems[0].yLabel) { + title = tooltipItems[0].yLabel; + } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) { + title = data.labels[tooltipItems[0].index]; + } + } + + return title; + }, + label: function(tooltipItem, data) { + var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || ''; + return datasetLabel + ': ' + tooltipItem.xLabel; + } + } + } + }; + + Chart.controllers.horizontalBar = Chart.controllers.bar.extend({ + updateElement: function(rectangle, index, reset) { + var me = this; + var meta = me.getMeta(); + var xScale = me.getScaleForId(meta.xAxisID); + var yScale = me.getScaleForId(meta.yAxisID); + var scaleBase = xScale.getBasePixel(); + var custom = rectangle.custom || {}; + var dataset = me.getDataset(); + var rectangleElementOptions = me.chart.options.elements.rectangle; + + helpers.extend(rectangle, { + // Utility + _xScale: xScale, + _yScale: yScale, + _datasetIndex: me.index, + _index: index, + + // Desired view properties + _model: { + x: reset ? scaleBase : me.calculateBarX(index, me.index), + y: me.calculateBarY(index, me.index), + + // Tooltip + label: me.chart.data.labels[index], + datasetLabel: dataset.label, + + // Appearance + base: reset ? scaleBase : me.calculateBarBase(me.index, index), + height: me.calculateBarHeight(index), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), + borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped, + borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), + borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) + }, + + draw: function() { + var ctx = this._chart.ctx; + var vm = this._view; + + var halfHeight = vm.height / 2, + topY = vm.y - halfHeight, + bottomY = vm.y + halfHeight, + right = vm.base - (vm.base - vm.x), + halfStroke = vm.borderWidth / 2; + + // Canvas doesn't allow us to stroke inside the width so we can + // adjust the sizes to fit if we're setting a stroke on the line + if (vm.borderWidth) { + topY += halfStroke; + bottomY -= halfStroke; + right += halfStroke; + } + + ctx.beginPath(); + + ctx.fillStyle = vm.backgroundColor; + ctx.strokeStyle = vm.borderColor; + ctx.lineWidth = vm.borderWidth; + + // Corner points, from bottom-left to bottom-right clockwise + // | 1 2 | + // | 0 3 | + var corners = [ + [vm.base, bottomY], + [vm.base, topY], + [right, topY], + [right, bottomY] + ]; + + // Find first (starting) corner with fallback to 'bottom' + var borders = ['bottom', 'left', 'top', 'right']; + var startCorner = borders.indexOf(vm.borderSkipped, 0); + if (startCorner === -1) { + startCorner = 0; + } + + function cornerAt(cornerIndex) { + return corners[(startCorner + cornerIndex) % 4]; + } + + // Draw rectangle from 'startCorner' + ctx.moveTo.apply(ctx, cornerAt(0)); + for (var i = 1; i < 4; i++) { + ctx.lineTo.apply(ctx, cornerAt(i)); + } + + ctx.fill(); + if (vm.borderWidth) { + ctx.stroke(); + } + }, + + inRange: function(mouseX, mouseY) { + var vm = this._view; + var inRange = false; + + if (vm) { + if (vm.x < vm.base) { + inRange = (mouseY >= vm.y - vm.height / 2 && mouseY <= vm.y + vm.height / 2) && (mouseX >= vm.x && mouseX <= vm.base); + } else { + inRange = (mouseY >= vm.y - vm.height / 2 && mouseY <= vm.y + vm.height / 2) && (mouseX >= vm.base && mouseX <= vm.x); + } + } + + return inRange; + } + }); + + rectangle.pivot(); + }, + + calculateBarBase: function(datasetIndex, index) { + var me = this; + var meta = me.getMeta(); + var xScale = me.getScaleForId(meta.xAxisID); + var base = 0; + + if (xScale.options.stacked) { + var chart = me.chart; + var datasets = chart.data.datasets; + var value = Number(datasets[datasetIndex].data[index]); + + for (var i = 0; i < datasetIndex; i++) { + var currentDs = datasets[i]; + var currentDsMeta = chart.getDatasetMeta(i); + if (currentDsMeta.bar && currentDsMeta.xAxisID === xScale.id && chart.isDatasetVisible(i)) { + var currentVal = Number(currentDs.data[index]); + base += value < 0 ? Math.min(currentVal, 0) : Math.max(currentVal, 0); + } + } + + return xScale.getPixelForValue(base); + } + + return xScale.getBasePixel(); + }, + + getRuler: function(index) { + var me = this; + var meta = me.getMeta(); + var yScale = me.getScaleForId(meta.yAxisID); + var datasetCount = me.getBarCount(); + + var tickHeight; + if (yScale.options.type === 'category') { + tickHeight = yScale.getPixelForTick(index + 1) - yScale.getPixelForTick(index); + } else { + // Average width + tickHeight = yScale.width / yScale.ticks.length; + } + var categoryHeight = tickHeight * yScale.options.categoryPercentage; + var categorySpacing = (tickHeight - (tickHeight * yScale.options.categoryPercentage)) / 2; + var fullBarHeight = categoryHeight / datasetCount; + + if (yScale.ticks.length !== me.chart.data.labels.length) { + var perc = yScale.ticks.length / me.chart.data.labels.length; + fullBarHeight = fullBarHeight * perc; + } + + var barHeight = fullBarHeight * yScale.options.barPercentage; + var barSpacing = fullBarHeight - (fullBarHeight * yScale.options.barPercentage); + + return { + datasetCount: datasetCount, + tickHeight: tickHeight, + categoryHeight: categoryHeight, + categorySpacing: categorySpacing, + fullBarHeight: fullBarHeight, + barHeight: barHeight, + barSpacing: barSpacing + }; + }, + + calculateBarHeight: function(index) { + var me = this; + var yScale = me.getScaleForId(me.getMeta().yAxisID); + if (yScale.options.barThickness) { + return yScale.options.barThickness; + } + var ruler = me.getRuler(index); + return yScale.options.stacked ? ruler.categoryHeight : ruler.barHeight; + }, + + calculateBarX: function(index, datasetIndex) { + var me = this; + var meta = me.getMeta(); + var xScale = me.getScaleForId(meta.xAxisID); + var value = Number(me.getDataset().data[index]); + + if (xScale.options.stacked) { + + var sumPos = 0, + sumNeg = 0; + + for (var i = 0; i < datasetIndex; i++) { + var ds = me.chart.data.datasets[i]; + var dsMeta = me.chart.getDatasetMeta(i); + if (dsMeta.bar && dsMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(i)) { + var stackedVal = Number(ds.data[index]); + if (stackedVal < 0) { + sumNeg += stackedVal || 0; + } else { + sumPos += stackedVal || 0; + } + } + } + + if (value < 0) { + return xScale.getPixelForValue(sumNeg + value); + } + return xScale.getPixelForValue(sumPos + value); + } + + return xScale.getPixelForValue(value); + }, + + calculateBarY: function(index, datasetIndex) { + var me = this; + var meta = me.getMeta(); + var yScale = me.getScaleForId(meta.yAxisID); + var barIndex = me.getBarIndex(datasetIndex); + + var ruler = me.getRuler(index); + var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo); + topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0; + + if (yScale.options.stacked) { + return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing; + } + + return topTick + + (ruler.barHeight / 2) + + ruler.categorySpacing + + (ruler.barHeight * barIndex) + + (ruler.barSpacing / 2) + + (ruler.barSpacing * barIndex); + } + }); +}; + +},{}],16:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.bubble = { + hover: { + mode: 'single' + }, + + scales: { + xAxes: [{ + type: 'linear', // bubble should probably use a linear scale by default + position: 'bottom', + id: 'x-axis-0' // need an ID so datasets can reference the scale + }], + yAxes: [{ + type: 'linear', + position: 'left', + id: 'y-axis-0' + }] + }, + + tooltips: { + callbacks: { + title: function() { + // Title doesn't make sense for scatter since we format the data as a point + return ''; + }, + label: function(tooltipItem, data) { + var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || ''; + var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; + return datasetLabel + ': (' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.r + ')'; + } + } + } + }; + + Chart.controllers.bubble = Chart.DatasetController.extend({ + + dataElementType: Chart.elements.Point, + + update: function(reset) { + var me = this; + var meta = me.getMeta(); + var points = meta.data; + + // Update Points + helpers.each(points, function(point, index) { + me.updateElement(point, index, reset); + }); + }, + + updateElement: function(point, index, reset) { + var me = this; + var meta = me.getMeta(); + var xScale = me.getScaleForId(meta.xAxisID); + var yScale = me.getScaleForId(meta.yAxisID); + + var custom = point.custom || {}; + var dataset = me.getDataset(); + var data = dataset.data[index]; + var pointElementOptions = me.chart.options.elements.point; + var dsIndex = me.index; + + helpers.extend(point, { + // Utility + _xScale: xScale, + _yScale: yScale, + _datasetIndex: dsIndex, + _index: index, + + // Desired view properties + _model: { + x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex, me.chart.isCombo), + y: reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex), + // Appearance + radius: reset ? 0 : custom.radius ? custom.radius : me.getRadius(data), + + // Tooltip + hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius) + } + }); + + // Trick to reset the styles of the point + Chart.DatasetController.prototype.removeHoverStyle.call(me, point, pointElementOptions); + + var model = point._model; + model.skip = custom.skip ? custom.skip : (isNaN(model.x) || isNaN(model.y)); + + point.pivot(); + }, + + getRadius: function(value) { + return value.r || this.chart.options.elements.point.radius; + }, + + setHoverStyle: function(point) { + var me = this; + Chart.DatasetController.prototype.setHoverStyle.call(me, point); + + // Radius + var dataset = me.chart.data.datasets[point._datasetIndex]; + var index = point._index; + var custom = point.custom || {}; + var model = point._model; + model.radius = custom.hoverRadius ? custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, me.chart.options.elements.point.hoverRadius)) + me.getRadius(dataset.data[index]); + }, + + removeHoverStyle: function(point) { + var me = this; + Chart.DatasetController.prototype.removeHoverStyle.call(me, point, me.chart.options.elements.point); + + var dataVal = me.chart.data.datasets[point._datasetIndex].data[point._index]; + var custom = point.custom || {}; + var model = point._model; + + model.radius = custom.radius ? custom.radius : me.getRadius(dataVal); + } + }); +}; + +},{}],17:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + var helpers = Chart.helpers, + defaults = Chart.defaults; + + defaults.doughnut = { + animation: { + // Boolean - Whether we animate the rotation of the Doughnut + animateRotate: true, + // Boolean - Whether we animate scaling the Doughnut from the centre + animateScale: false + }, + aspectRatio: 1, + hover: { + mode: 'single' + }, + legendCallback: function(chart) { + var text = []; + text.push('
    '); + + var data = chart.data; + var datasets = data.datasets; + var labels = data.labels; + + if (datasets.length) { + for (var i = 0; i < datasets[0].data.length; ++i) { + text.push('
  • '); + if (labels[i]) { + text.push(labels[i]); + } + text.push('
  • '); + } + } + + text.push('
'); + return text.join(''); + }, + legend: { + labels: { + generateLabels: function(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i]; + var custom = arc && arc.custom || {}; + var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; + var arcOpts = chart.options.elements.arc; + var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); + var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); + var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); + + return { + text: label, + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, + + // Extra data used for toggling the correct item + index: i + }; + }); + } + return []; + } + }, + + onClick: function(e, legendItem) { + var index = legendItem.index; + var chart = this.chart; + var i, ilen, meta; + + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + // toggle visibility of index if exists + if (meta.data[index]) { + meta.data[index].hidden = !meta.data[index].hidden; + } + } + + chart.update(); + } + }, + + // The percentage of the chart that we cut out of the middle. + cutoutPercentage: 50, + + // The rotation of the chart, where the first data arc begins. + rotation: Math.PI * -0.5, + + // The total circumference of the chart. + circumference: Math.PI * 2.0, + + // Need to override these to give a nice default + tooltips: { + callbacks: { + title: function() { + return ''; + }, + label: function(tooltipItem, data) { + return data.labels[tooltipItem.index] + ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; + } + } + } + }; + + defaults.pie = helpers.clone(defaults.doughnut); + helpers.extend(defaults.pie, { + cutoutPercentage: 0 + }); + + + Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({ + + dataElementType: Chart.elements.Arc, + + linkScales: helpers.noop, + + // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly + getRingIndex: function(datasetIndex) { + var ringIndex = 0; + + for (var j = 0; j < datasetIndex; ++j) { + if (this.chart.isDatasetVisible(j)) { + ++ringIndex; + } + } + + return ringIndex; + }, + + update: function(reset) { + var me = this; + var chart = me.chart, + chartArea = chart.chartArea, + opts = chart.options, + arcOpts = opts.elements.arc, + availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth, + availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth, + minSize = Math.min(availableWidth, availableHeight), + offset = { + x: 0, + y: 0 + }, + meta = me.getMeta(), + cutoutPercentage = opts.cutoutPercentage, + circumference = opts.circumference; + + // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc + if (circumference < Math.PI * 2.0) { + var startAngle = opts.rotation % (Math.PI * 2.0); + startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0); + var endAngle = startAngle + circumference; + var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)}; + var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)}; + var contains0 = (startAngle <= 0 && 0 <= endAngle) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle); + var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle); + var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle); + var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle); + var cutout = cutoutPercentage / 100.0; + var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))}; + var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))}; + var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5}; + minSize = Math.min(availableWidth / size.width, availableHeight / size.height); + offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5}; + } + + chart.borderWidth = me.getMaxBorderWidth(meta.data); + chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0); + chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 1, 0); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); + chart.offsetX = offset.x * chart.outerRadius; + chart.offsetY = offset.y * chart.outerRadius; + + meta.total = me.calculateTotal(); + + me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index)); + me.innerRadius = me.outerRadius - chart.radiusLength; + + helpers.each(meta.data, function(arc, index) { + me.updateElement(arc, index, reset); + }); + }, + + updateElement: function(arc, index, reset) { + var me = this; + var chart = me.chart, + chartArea = chart.chartArea, + opts = chart.options, + animationOpts = opts.animation, + centerX = (chartArea.left + chartArea.right) / 2, + centerY = (chartArea.top + chartArea.bottom) / 2, + startAngle = opts.rotation, // non reset case handled later + endAngle = opts.rotation, // non reset case handled later + dataset = me.getDataset(), + circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)), + innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius, + outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius, + valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; + + helpers.extend(arc, { + // Utility + _datasetIndex: me.index, + _index: index, + + // Desired view properties + _model: { + x: centerX + chart.offsetX, + y: centerY + chart.offsetY, + startAngle: startAngle, + endAngle: endAngle, + circumference: circumference, + outerRadius: outerRadius, + innerRadius: innerRadius, + label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index]) + } + }); + + var model = arc._model; + // Resets the visual styles + this.removeHoverStyle(arc); + + // Set correct angles if not resetting + if (!reset || !animationOpts.animateRotate) { + if (index === 0) { + model.startAngle = opts.rotation; + } else { + model.startAngle = me.getMeta().data[index - 1]._model.endAngle; + } + + model.endAngle = model.startAngle + model.circumference; + } + + arc.pivot(); + }, + + removeHoverStyle: function(arc) { + Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); + }, + + calculateTotal: function() { + var dataset = this.getDataset(); + var meta = this.getMeta(); + var total = 0; + var value; + + helpers.each(meta.data, function(element, index) { + value = dataset.data[index]; + if (!isNaN(value) && !element.hidden) { + total += Math.abs(value); + } + }); + + /* if (total === 0) { + total = NaN; + }*/ + + return total; + }, + + calculateCircumference: function(value) { + var total = this.getMeta().total; + if (total > 0 && !isNaN(value)) { + return (Math.PI * 2.0) * (value / total); + } + return 0; + }, + + // gets the max border or hover width to properly scale pie charts + getMaxBorderWidth: function(elements) { + var max = 0, + index = this.index, + length = elements.length, + borderWidth, + hoverWidth; + + for (var i = 0; i < length; i++) { + borderWidth = elements[i]._model ? elements[i]._model.borderWidth : 0; + hoverWidth = elements[i]._chart ? elements[i]._chart.config.data.datasets[index].hoverBorderWidth : 0; + + max = borderWidth > max ? borderWidth : max; + max = hoverWidth > max ? hoverWidth : max; + } + return max; + } + }); +}; + +},{}],18:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.line = { + showLines: true, + spanGaps: false, + + hover: { + mode: 'label' + }, + + scales: { + xAxes: [{ + type: 'category', + id: 'x-axis-0' + }], + yAxes: [{ + type: 'linear', + id: 'y-axis-0' + }] + } + }; + + function lineEnabled(dataset, options) { + return helpers.getValueOrDefault(dataset.showLine, options.showLines); + } + + Chart.controllers.line = Chart.DatasetController.extend({ + + datasetElementType: Chart.elements.Line, + + dataElementType: Chart.elements.Point, + + addElementAndReset: function(index) { + var me = this; + var options = me.chart.options; + var meta = me.getMeta(); + + Chart.DatasetController.prototype.addElementAndReset.call(me, index); + + // Make sure bezier control points are updated + if (lineEnabled(me.getDataset(), options) && meta.dataset._model.tension !== 0) { + me.updateBezierControlPoints(); + } + }, + + update: function(reset) { + var me = this; + var meta = me.getMeta(); + var line = meta.dataset; + var points = meta.data || []; + var options = me.chart.options; + var lineElementOptions = options.elements.line; + var scale = me.getScaleForId(meta.yAxisID); + var i, ilen, custom; + var dataset = me.getDataset(); + var showLine = lineEnabled(dataset, options); + + // Update Line + if (showLine) { + custom = line.custom || {}; + + // Compatibility: If the properties are defined with only the old name, use those values + if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) { + dataset.lineTension = dataset.tension; + } + + // Utility + line._scale = scale; + line._datasetIndex = me.index; + // Data + line._children = points; + // Model + line._model = { + // Appearance + // The default behavior of lines is to break at null values, according + // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158 + // This option gives linse the ability to span gaps + spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps, + tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor), + borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth), + borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor), + borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle), + borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash), + borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset), + borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle), + fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill), + steppedLine: custom.steppedLine ? custom.steppedLine : helpers.getValueOrDefault(dataset.steppedLine, lineElementOptions.stepped), + cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.getValueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode), + // Scale + scaleTop: scale.top, + scaleBottom: scale.bottom, + scaleZero: scale.getBasePixel() + }; + + line.pivot(); + } + + // Update Points + for (i=0, ilen=points.length; i'); + + var data = chart.data; + var datasets = data.datasets; + var labels = data.labels; + + if (datasets.length) { + for (var i = 0; i < datasets[0].data.length; ++i) { + text.push('
  • '); + if (labels[i]) { + text.push(labels[i]); + } + text.push('
  • '); + } + } + + text.push(''); + return text.join(''); + }, + legend: { + labels: { + generateLabels: function(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i]; + var custom = arc.custom || {}; + var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; + var arcOpts = chart.options.elements.arc; + var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); + var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); + var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); + + return { + text: label, + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, + + // Extra data used for toggling the correct item + index: i + }; + }); + } + return []; + } + }, + + onClick: function(e, legendItem) { + var index = legendItem.index; + var chart = this.chart; + var i, ilen, meta; + + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + meta.data[index].hidden = !meta.data[index].hidden; + } + + chart.update(); + } + }, + + // Need to override these to give a nice default + tooltips: { + callbacks: { + title: function() { + return ''; + }, + label: function(tooltipItem, data) { + return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel; + } + } + } + }; + + Chart.controllers.polarArea = Chart.DatasetController.extend({ + + dataElementType: Chart.elements.Arc, + + linkScales: helpers.noop, + + update: function(reset) { + var me = this; + var chart = me.chart; + var chartArea = chart.chartArea; + var meta = me.getMeta(); + var opts = chart.options; + var arcOpts = opts.elements.arc; + var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0); + chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); + + me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index); + me.innerRadius = me.outerRadius - chart.radiusLength; + + meta.count = me.countVisibleElements(); + + helpers.each(meta.data, function(arc, index) { + me.updateElement(arc, index, reset); + }); + }, + + updateElement: function(arc, index, reset) { + var me = this; + var chart = me.chart; + var dataset = me.getDataset(); + var opts = chart.options; + var animationOpts = opts.animation; + var scale = chart.scale; + var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; + var labels = chart.data.labels; + + var circumference = me.calculateCircumference(dataset.data[index]); + var centerX = scale.xCenter; + var centerY = scale.yCenter; + + // If there is NaN data before us, we need to calculate the starting angle correctly. + // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data + var visibleCount = 0; + var meta = me.getMeta(); + for (var i = 0; i < index; ++i) { + if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) { + ++visibleCount; + } + } + + // var negHalfPI = -0.5 * Math.PI; + var datasetStartAngle = opts.startAngle; + var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); + var startAngle = datasetStartAngle + (circumference * visibleCount); + var endAngle = startAngle + (arc.hidden ? 0 : circumference); + + var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); + + helpers.extend(arc, { + // Utility + _datasetIndex: me.index, + _index: index, + _scale: scale, + + // Desired view properties + _model: { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius: reset ? resetRadius : distance, + startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle, + endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle, + label: getValueAtIndexOrDefault(labels, index, labels[index]) + } + }); + + // Apply border and fill style + me.removeHoverStyle(arc); + + arc.pivot(); + }, + + removeHoverStyle: function(arc) { + Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); + }, + + countVisibleElements: function() { + var dataset = this.getDataset(); + var meta = this.getMeta(); + var count = 0; + + helpers.each(meta.data, function(element, index) { + if (!isNaN(dataset.data[index]) && !element.hidden) { + count++; + } + }); + + return count; + }, + + calculateCircumference: function(value) { + var count = this.getMeta().count; + if (count > 0 && !isNaN(value)) { + return (2 * Math.PI) / count; + } + return 0; + } + }); +}; + +},{}],20:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.radar = { + scale: { + type: 'radialLinear' + }, + elements: { + line: { + tension: 0 // no bezier in radar + } + } + }; + + Chart.controllers.radar = Chart.DatasetController.extend({ + + datasetElementType: Chart.elements.Line, + + dataElementType: Chart.elements.Point, + + linkScales: helpers.noop, + + addElementAndReset: function(index) { + Chart.DatasetController.prototype.addElementAndReset.call(this, index); + + // Make sure bezier control points are updated + this.updateBezierControlPoints(); + }, + + update: function(reset) { + var me = this; + var meta = me.getMeta(); + var line = meta.dataset; + var points = meta.data; + var custom = line.custom || {}; + var dataset = me.getDataset(); + var lineElementOptions = me.chart.options.elements.line; + var scale = me.chart.scale; + + // Compatibility: If the properties are defined with only the old name, use those values + if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) { + dataset.lineTension = dataset.tension; + } + + helpers.extend(meta.dataset, { + // Utility + _datasetIndex: me.index, + // Data + _children: points, + _loop: true, + // Model + _model: { + // Appearance + tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor), + borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth), + borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor), + fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill), + borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle), + borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash), + borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset), + borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle), + + // Scale + scaleTop: scale.top, + scaleBottom: scale.bottom, + scaleZero: scale.getBasePosition() + } + }); + + meta.dataset.pivot(); + + // Update Points + helpers.each(points, function(point, index) { + me.updateElement(point, index, reset); + }, me); + + + // Update bezier control points + me.updateBezierControlPoints(); + }, + updateElement: function(point, index, reset) { + var me = this; + var custom = point.custom || {}; + var dataset = me.getDataset(); + var scale = me.chart.scale; + var pointElementOptions = me.chart.options.elements.point; + var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]); + + helpers.extend(point, { + // Utility + _datasetIndex: me.index, + _index: index, + _scale: scale, + + // Desired view properties + _model: { + x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales + y: reset ? scale.yCenter : pointPosition.y, + + // Appearance + tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.tension, me.chart.options.elements.line.tension), + radius: custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor), + borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor), + borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth), + pointStyle: custom.pointStyle ? custom.pointStyle : helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle), + + // Tooltip + hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius) + } + }); + + point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); + }, + updateBezierControlPoints: function() { + var chartArea = this.chart.chartArea; + var meta = this.getMeta(); + + helpers.each(meta.data, function(point, index) { + var model = point._model; + var controlPoints = helpers.splineCurve( + helpers.previousItem(meta.data, index, true)._model, + model, + helpers.nextItem(meta.data, index, true)._model, + model.tension + ); + + // Prevent the bezier going outside of the bounds of the graph + model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left); + model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top); + + model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left); + model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top); + + // Now pivot the point for animation + point.pivot(); + }); + }, + + draw: function(ease) { + var meta = this.getMeta(); + var easingDecimal = ease || 1; + + // Transition Point Locations + helpers.each(meta.data, function(point) { + point.transition(easingDecimal); + }); + + // Transition and Draw the line + meta.dataset.transition(easingDecimal).draw(); + + // Draw the points + helpers.each(meta.data, function(point) { + point.draw(); + }); + }, + + setHoverStyle: function(point) { + // Point + var dataset = this.chart.data.datasets[point._datasetIndex]; + var custom = point.custom || {}; + var index = point._index; + var model = point._model; + + model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius); + model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); + model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor)); + model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth); + }, + + removeHoverStyle: function(point) { + var dataset = this.chart.data.datasets[point._datasetIndex]; + var custom = point.custom || {}; + var index = point._index; + var model = point._model; + var pointElementOptions = this.chart.options.elements.point; + + model.radius = custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.radius, index, pointElementOptions.radius); + model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor); + model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor); + model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth); + } + }); +}; + +},{}],21:[function(require,module,exports){ +/* global window: false */ +'use strict'; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + + Chart.defaults.global.animation = { + duration: 1000, + easing: 'easeOutQuart', + onProgress: helpers.noop, + onComplete: helpers.noop + }; + + Chart.Animation = Chart.Element.extend({ + currentStep: null, // the current animation step + numSteps: 60, // default number of steps + easing: '', // the easing to use for this animation + render: null, // render function used by the animation service + + onAnimationProgress: null, // user specified callback to fire on each step of the animation + onAnimationComplete: null // user specified callback to fire when the animation finishes + }); + + Chart.animationService = { + frameDuration: 17, + animations: [], + dropFrames: 0, + request: null, + addAnimation: function(chartInstance, animationObject, duration, lazy) { + var me = this; + + if (!lazy) { + chartInstance.animating = true; + } + + for (var index = 0; index < me.animations.length; ++index) { + if (me.animations[index].chartInstance === chartInstance) { + // replacing an in progress animation + me.animations[index].animationObject = animationObject; + return; + } + } + + me.animations.push({ + chartInstance: chartInstance, + animationObject: animationObject + }); + + // If there are no animations queued, manually kickstart a digest, for lack of a better word + if (me.animations.length === 1) { + me.requestAnimationFrame(); + } + }, + // Cancel the animation for a given chart instance + cancelAnimation: function(chartInstance) { + var index = helpers.findIndex(this.animations, function(animationWrapper) { + return animationWrapper.chartInstance === chartInstance; + }); + + if (index !== -1) { + this.animations.splice(index, 1); + chartInstance.animating = false; + } + }, + requestAnimationFrame: function() { + var me = this; + if (me.request === null) { + // Skip animation frame requests until the active one is executed. + // This can happen when processing mouse events, e.g. 'mousemove' + // and 'mouseout' events will trigger multiple renders. + me.request = helpers.requestAnimFrame.call(window, function() { + me.request = null; + me.startDigest(); + }); + } + }, + startDigest: function() { + var me = this; + + var startTime = Date.now(); + var framesToDrop = 0; + + if (me.dropFrames > 1) { + framesToDrop = Math.floor(me.dropFrames); + me.dropFrames = me.dropFrames % 1; + } + + var i = 0; + while (i < me.animations.length) { + if (me.animations[i].animationObject.currentStep === null) { + me.animations[i].animationObject.currentStep = 0; + } + + me.animations[i].animationObject.currentStep += 1 + framesToDrop; + + if (me.animations[i].animationObject.currentStep > me.animations[i].animationObject.numSteps) { + me.animations[i].animationObject.currentStep = me.animations[i].animationObject.numSteps; + } + + me.animations[i].animationObject.render(me.animations[i].chartInstance, me.animations[i].animationObject); + if (me.animations[i].animationObject.onAnimationProgress && me.animations[i].animationObject.onAnimationProgress.call) { + me.animations[i].animationObject.onAnimationProgress.call(me.animations[i].chartInstance, me.animations[i]); + } + + if (me.animations[i].animationObject.currentStep === me.animations[i].animationObject.numSteps) { + if (me.animations[i].animationObject.onAnimationComplete && me.animations[i].animationObject.onAnimationComplete.call) { + me.animations[i].animationObject.onAnimationComplete.call(me.animations[i].chartInstance, me.animations[i]); + } + + // executed the last frame. Remove the animation. + me.animations[i].chartInstance.animating = false; + + me.animations.splice(i, 1); + } else { + ++i; + } + } + + var endTime = Date.now(); + var dropFrames = (endTime - startTime) / me.frameDuration; + + me.dropFrames += dropFrames; + + // Do we have more stuff to animate? + if (me.animations.length > 0) { + me.requestAnimationFrame(); + } + } + }; +}; + +},{}],22:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + // Global Chart canvas helpers object for drawing items to canvas + var helpers = Chart.canvasHelpers = {}; + + helpers.drawPoint = function(ctx, pointStyle, radius, x, y) { + var type, edgeLength, xOffset, yOffset, height, size; + + if (typeof pointStyle === 'object') { + type = pointStyle.toString(); + if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { + ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2); + return; + } + } + + if (isNaN(radius) || radius <= 0) { + return; + } + + switch (pointStyle) { + // Default includes circle + default: + ctx.beginPath(); + ctx.arc(x, y, radius, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + break; + case 'triangle': + ctx.beginPath(); + edgeLength = 3 * radius / Math.sqrt(3); + height = edgeLength * Math.sqrt(3) / 2; + ctx.moveTo(x - edgeLength / 2, y + height / 3); + ctx.lineTo(x + edgeLength / 2, y + height / 3); + ctx.lineTo(x, y - 2 * height / 3); + ctx.closePath(); + ctx.fill(); + break; + case 'rect': + size = 1 / Math.SQRT2 * radius; + ctx.beginPath(); + ctx.fillRect(x - size, y - size, 2 * size, 2 * size); + ctx.strokeRect(x - size, y - size, 2 * size, 2 * size); + break; + case 'rectRot': + size = 1 / Math.SQRT2 * radius; + ctx.beginPath(); + ctx.moveTo(x - size, y); + ctx.lineTo(x, y + size); + ctx.lineTo(x + size, y); + ctx.lineTo(x, y - size); + ctx.closePath(); + ctx.fill(); + break; + case 'cross': + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y - radius); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + case 'crossRot': + ctx.beginPath(); + xOffset = Math.cos(Math.PI / 4) * radius; + yOffset = Math.sin(Math.PI / 4) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x - xOffset, y + yOffset); + ctx.lineTo(x + xOffset, y - yOffset); + ctx.closePath(); + break; + case 'star': + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y - radius); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + xOffset = Math.cos(Math.PI / 4) * radius; + yOffset = Math.sin(Math.PI / 4) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x - xOffset, y + yOffset); + ctx.lineTo(x + xOffset, y - yOffset); + ctx.closePath(); + break; + case 'line': + ctx.beginPath(); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + case 'dash': + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + } + + ctx.stroke(); + }; +}; + +},{}],23:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + var helpers = Chart.helpers; + // Create a dictionary of chart types, to allow for extension of existing types + Chart.types = {}; + + // Store a reference to each instance - allowing us to globally resize chart instances on window resize. + // Destroy method on the chart will remove the instance of the chart from this reference. + Chart.instances = {}; + + // Controllers available for dataset visualization eg. bar, line, slice, etc. + Chart.controllers = {}; + + /** + * @class Chart.Controller + * The main controller of a chart. + */ + Chart.Controller = function(instance) { + + this.chart = instance; + this.config = instance.config; + this.options = this.config.options = helpers.configMerge(Chart.defaults.global, Chart.defaults[this.config.type], this.config.options || {}); + this.id = helpers.uid(); + + Object.defineProperty(this, 'data', { + get: function() { + return this.config.data; + } + }); + + // Add the chart instance to the global namespace + Chart.instances[this.id] = this; + + if (this.options.responsive) { + // Silent resize before chart draws + this.resize(true); + } + + this.initialize(); + + return this; + }; + + helpers.extend(Chart.Controller.prototype, /** @lends Chart.Controller */ { + + initialize: function() { + var me = this; + // Before init plugin notification + Chart.plugins.notify('beforeInit', [me]); + + me.bindEvents(); + + // Make sure controllers are built first so that each dataset is bound to an axis before the scales + // are built + me.ensureScalesHaveIDs(); + me.buildOrUpdateControllers(); + me.buildScales(); + me.updateLayout(); + me.resetElements(); + me.initToolTip(); + me.update(); + + // After init plugin notification + Chart.plugins.notify('afterInit', [me]); + + return me; + }, + + clear: function() { + helpers.clear(this.chart); + return this; + }, + + stop: function() { + // Stops any current animation loop occuring + Chart.animationService.cancelAnimation(this); + return this; + }, + + resize: function(silent) { + var me = this; + var chart = me.chart; + var canvas = chart.canvas; + var newWidth = helpers.getMaximumWidth(canvas); + var aspectRatio = chart.aspectRatio; + var newHeight = (me.options.maintainAspectRatio && isNaN(aspectRatio) === false && isFinite(aspectRatio) && aspectRatio !== 0) ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas); + + var sizeChanged = chart.width !== newWidth || chart.height !== newHeight; + + if (!sizeChanged) { + return me; + } + + canvas.width = chart.width = newWidth; + canvas.height = chart.height = newHeight; + + helpers.retinaScale(chart); + + // Notify any plugins about the resize + var newSize = {width: newWidth, height: newHeight}; + Chart.plugins.notify('resize', [me, newSize]); + + // Notify of resize + if (me.options.onResize) { + me.options.onResize(me, newSize); + } + + if (!silent) { + me.stop(); + me.update(me.options.responsiveAnimationDuration); + } + + return me; + }, + + ensureScalesHaveIDs: function() { + var options = this.options; + var scalesOptions = options.scales || {}; + var scaleOptions = options.scale; + + helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) { + xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index); + }); + + helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) { + yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index); + }); + + if (scaleOptions) { + scaleOptions.id = scaleOptions.id || 'scale'; + } + }, + + /** + * Builds a map of scale ID to scale object for future lookup. + */ + buildScales: function() { + var me = this; + var options = me.options; + var scales = me.scales = {}; + var items = []; + + if (options.scales) { + items = items.concat( + (options.scales.xAxes || []).map(function(xAxisOptions) { + return {options: xAxisOptions, dtype: 'category'}; + }), + (options.scales.yAxes || []).map(function(yAxisOptions) { + return {options: yAxisOptions, dtype: 'linear'}; + }) + ); + } + + if (options.scale) { + items.push({options: options.scale, dtype: 'radialLinear', isDefault: true}); + } + + helpers.each(items, function(item) { + var scaleOptions = item.options; + var scaleType = helpers.getValueOrDefault(scaleOptions.type, item.dtype); + var scaleClass = Chart.scaleService.getScaleConstructor(scaleType); + if (!scaleClass) { + return; + } + + var scale = new scaleClass({ + id: scaleOptions.id, + options: scaleOptions, + ctx: me.chart.ctx, + chart: me + }); + + scales[scale.id] = scale; + + // TODO(SB): I think we should be able to remove this custom case (options.scale) + // and consider it as a regular scale part of the "scales"" map only! This would + // make the logic easier and remove some useless? custom code. + if (item.isDefault) { + me.scale = scale; + } + }); + + Chart.scaleService.addScalesToLayout(this); + }, + + updateLayout: function() { + Chart.layoutService.update(this, this.chart.width, this.chart.height); + }, + + buildOrUpdateControllers: function() { + var me = this; + var types = []; + var newControllers = []; + + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + var meta = me.getDatasetMeta(datasetIndex); + if (!meta.type) { + meta.type = dataset.type || me.config.type; + } + + types.push(meta.type); + + if (meta.controller) { + meta.controller.updateIndex(datasetIndex); + } else { + meta.controller = new Chart.controllers[meta.type](me, datasetIndex); + newControllers.push(meta.controller); + } + }, me); + + if (types.length > 1) { + for (var i = 1; i < types.length; i++) { + if (types[i] !== types[i - 1]) { + me.isCombo = true; + break; + } + } + } + + return newControllers; + }, + + resetElements: function() { + var me = this; + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + me.getDatasetMeta(datasetIndex).controller.reset(); + }, me); + }, + + update: function(animationDuration, lazy) { + var me = this; + Chart.plugins.notify('beforeUpdate', [me]); + + // In case the entire data object changed + me.tooltip._data = me.data; + + // Make sure dataset controllers are updated and new controllers are reset + var newControllers = me.buildOrUpdateControllers(); + + // Make sure all dataset controllers have correct meta data counts + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements(); + }, me); + + Chart.layoutService.update(me, me.chart.width, me.chart.height); + + // Apply changes to the dataets that require the scales to have been calculated i.e BorderColor chages + Chart.plugins.notify('afterScaleUpdate', [me]); + + // Can only reset the new controllers after the scales have been updated + helpers.each(newControllers, function(controller) { + controller.reset(); + }); + + me.updateDatasets(); + + // Do this before render so that any plugins that need final scale updates can use it + Chart.plugins.notify('afterUpdate', [me]); + + me.render(animationDuration, lazy); + }, + + /** + * @method beforeDatasetsUpdate + * @description Called before all datasets are updated. If a plugin returns false, + * the datasets update will be cancelled until another chart update is triggered. + * @param {Object} instance the chart instance being updated. + * @returns {Boolean} false to cancel the datasets update. + * @memberof Chart.PluginBase + * @since version 2.1.5 + * @instance + */ + + /** + * @method afterDatasetsUpdate + * @description Called after all datasets have been updated. Note that this + * extension will not be called if the datasets update has been cancelled. + * @param {Object} instance the chart instance being updated. + * @memberof Chart.PluginBase + * @since version 2.1.5 + * @instance + */ + + /** + * Updates all datasets unless a plugin returns false to the beforeDatasetsUpdate + * extension, in which case no datasets will be updated and the afterDatasetsUpdate + * notification will be skipped. + * @protected + * @instance + */ + updateDatasets: function() { + var me = this; + var i, ilen; + + if (Chart.plugins.notify('beforeDatasetsUpdate', [me])) { + for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me.getDatasetMeta(i).controller.update(); + } + + Chart.plugins.notify('afterDatasetsUpdate', [me]); + } + }, + + render: function(duration, lazy) { + var me = this; + Chart.plugins.notify('beforeRender', [me]); + + var animationOptions = me.options.animation; + if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) { + var animation = new Chart.Animation(); + animation.numSteps = (duration || animationOptions.duration) / 16.66; // 60 fps + animation.easing = animationOptions.easing; + + // render function + animation.render = function(chartInstance, animationObject) { + var easingFunction = helpers.easingEffects[animationObject.easing]; + var stepDecimal = animationObject.currentStep / animationObject.numSteps; + var easeDecimal = easingFunction(stepDecimal); + + chartInstance.draw(easeDecimal, stepDecimal, animationObject.currentStep); + }; + + // user events + animation.onAnimationProgress = animationOptions.onProgress; + animation.onAnimationComplete = animationOptions.onComplete; + + Chart.animationService.addAnimation(me, animation, duration, lazy); + } else { + me.draw(); + if (animationOptions && animationOptions.onComplete && animationOptions.onComplete.call) { + animationOptions.onComplete.call(me); + } + } + return me; + }, + + draw: function(ease) { + var me = this; + var easingDecimal = ease || 1; + me.clear(); + + Chart.plugins.notify('beforeDraw', [me, easingDecimal]); + + // Draw all the scales + helpers.each(me.boxes, function(box) { + box.draw(me.chartArea); + }, me); + if (me.scale) { + me.scale.draw(); + } + + Chart.plugins.notify('beforeDatasetsDraw', [me, easingDecimal]); + + // Draw each dataset via its respective controller (reversed to support proper line stacking) + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + if (me.isDatasetVisible(datasetIndex)) { + me.getDatasetMeta(datasetIndex).controller.draw(ease); + } + }, me, true); + + Chart.plugins.notify('afterDatasetsDraw', [me, easingDecimal]); + + // Finally draw the tooltip + me.tooltip.transition(easingDecimal).draw(); + + Chart.plugins.notify('afterDraw', [me, easingDecimal]); + }, + + // Get the single element that was clicked on + // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw + getElementAtEvent: function(e) { + var me = this; + var eventPosition = helpers.getRelativePosition(e, me.chart); + var elementsArray = []; + + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + if (me.isDatasetVisible(datasetIndex)) { + var meta = me.getDatasetMeta(datasetIndex); + helpers.each(meta.data, function(element) { + if (element.inRange(eventPosition.x, eventPosition.y)) { + elementsArray.push(element); + return elementsArray; + } + }); + } + }); + + return elementsArray.slice(0, 1); + }, + + getElementsAtEvent: function(e) { + var me = this; + var eventPosition = helpers.getRelativePosition(e, me.chart); + var elementsArray = []; + + var found = function() { + if (me.data.datasets) { + for (var i = 0; i < me.data.datasets.length; i++) { + var meta = me.getDatasetMeta(i); + if (me.isDatasetVisible(i)) { + for (var j = 0; j < meta.data.length; j++) { + if (meta.data[j].inRange(eventPosition.x, eventPosition.y)) { + return meta.data[j]; + } + } + } + } + } + }.call(me); + + if (!found) { + return elementsArray; + } + + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + if (me.isDatasetVisible(datasetIndex)) { + var meta = me.getDatasetMeta(datasetIndex), + element = meta.data[found._index]; + if (element && !element._view.skip) { + elementsArray.push(element); + } + } + }, me); + + return elementsArray; + }, + + getElementsAtXAxis: function(e) { + var me = this; + var eventPosition = helpers.getRelativePosition(e, me.chart); + var elementsArray = []; + + var found = function() { + if (me.data.datasets) { + for (var i = 0; i < me.data.datasets.length; i++) { + var meta = me.getDatasetMeta(i); + if (me.isDatasetVisible(i)) { + for (var j = 0; j < meta.data.length; j++) { + if (meta.data[j].inLabelRange(eventPosition.x, eventPosition.y)) { + return meta.data[j]; + } + } + } + } + } + }.call(me); + + if (!found) { + return elementsArray; + } + + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + if (me.isDatasetVisible(datasetIndex)) { + var meta = me.getDatasetMeta(datasetIndex); + var index = helpers.findIndex(meta.data, function(it) { + return found._model.x === it._model.x; + }); + if (index !== -1 && !meta.data[index]._view.skip) { + elementsArray.push(meta.data[index]); + } + } + }, me); + + return elementsArray; + }, + + getElementsAtEventForMode: function(e, mode) { + var me = this; + switch (mode) { + case 'single': + return me.getElementAtEvent(e); + case 'label': + return me.getElementsAtEvent(e); + case 'dataset': + return me.getDatasetAtEvent(e); + case 'x-axis': + return me.getElementsAtXAxis(e); + default: + return e; + } + }, + + getDatasetAtEvent: function(e) { + var elementsArray = this.getElementAtEvent(e); + + if (elementsArray.length > 0) { + elementsArray = this.getDatasetMeta(elementsArray[0]._datasetIndex).data; + } + + return elementsArray; + }, + + getDatasetMeta: function(datasetIndex) { + var me = this; + var dataset = me.data.datasets[datasetIndex]; + if (!dataset._meta) { + dataset._meta = {}; + } + + var meta = dataset._meta[me.id]; + if (!meta) { + meta = dataset._meta[me.id] = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, // See isDatasetVisible() comment + xAxisID: null, + yAxisID: null + }; + } + + return meta; + }, + + getVisibleDatasetCount: function() { + var count = 0; + for (var i = 0, ilen = this.data.datasets.length; i