diff --git a/dist/cedar.js b/dist/cedar.js
new file mode 100644
index 00000000..da0cc7ef
--- /dev/null
+++ b/dist/cedar.js
@@ -0,0 +1,1203 @@
+/**
+* arcgis-cedar - v0.8.2 - Wed Jan 11 2017 11:48:57 GMT-0500 (EST)
+* Copyright (c) 2017 Environmental Systems Research Institute, Inc.
+* Apache-2.0
+*/
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('d3'), require('vega')) :
+ typeof define === 'function' && define.amd ? define(['d3', 'vega'], factory) :
+ (global.Cedar = factory(global.d3,global.vg));
+}(this, (function (d3,vg) { 'use strict';
+
+var version = "0.8.2";
+
+/**
+ * Merges n objects
+ * @param {object} source Empty object that other objects will be merged into
+ * @return {Object} Merged objects
+ */
+function mixin (source) {
+ var i$1 = arguments.length, argsArray = Array(i$1);
+ while ( i$1-- ) argsArray[i$1] = arguments[i$1];
+
+ var args = [].concat( argsArray );
+ for (var i = 1; i < args.length; i++) {
+ d3.entries(args[i]).forEach(function (p) {
+ source[p.key] = p.value;
+ });
+ }
+ return source;
+}
+
+/**
+ * Recursively merge properties of two objects
+ */
+function mergeRecursive (obj1, obj2) {
+ for (var p in obj2) {
+ if (obj2.hasOwnProperty(p)) {
+ try {
+ // Property in destination object set; update its value.
+ if (obj2[p].constructor === Object || obj2[p].constructor === Array) {
+ obj1[p] = mergeRecursive(obj1[p], obj2[p]);
+ } else {
+ obj1[p] = obj2[p];
+ }
+ } catch (e) {
+ // Property in destination object not set; create it and set its value
+ obj1[p] = obj2[p];
+ }
+ }
+ }
+ return obj1;
+}
+
+/**
+ * Token replacement on a string
+ * @param {string} template string template
+ * @param {object} params Object hash that maps to the tokens to be replaced
+ * @return {string} string with values replaced
+ */
+function supplant (template, params) {
+ var t = template.replace(/{([^{}]*)}/g,
+ function (a, b) {
+ var r = getTokenValue(params, b);
+
+ return typeof r === 'string' || typeof r === 'number' ? r : a;
+ }
+ );
+ return t.replace(/"{([^{}]*)}"/g,
+ function (a, b) {
+ var r = getTokenValue(params, b);
+ return (!!r && r.constructor === Array) ? JSON.stringify(r) : a;
+ });
+}
+
+/**
+ * Get the value of a token from a hash
+ * @param {object} tokens Hash {a: 'a', b: { c: 'c'} }
+ * @param {string} tokenName Property name: 'a' would yield 'a', 'b.c' would yield 'c'
+ * @return {Any} Returns value contained within property
+ * Pulled from gulp-token-replace (MIT license)
+ * https://github.com/Pictela/gulp-token-replace/blob/master/index.js
+ */
+function getTokenValue (tokens, tokenName) {
+ var tmpTokens = tokens;
+ var tokenNameParts = tokenName.split('.');
+ for (var i = 0; i < tokenNameParts.length; i++) {
+ if (tmpTokens.hasOwnProperty(tokenNameParts[i])) {
+ tmpTokens = tmpTokens[tokenNameParts[i]];
+ } else {
+ return null;
+ }
+ }
+ return tmpTokens;
+}
+
+ /**
+ * Helper function that validates that the
+ * mappings hash contains values for all
+ * the inputs
+ * @param {array} inputs Array of inputs
+ * @param {object} mappings Hash of mappings
+ * @return {array} Missing mappings
+ * @access private
+ */
+function validateMappings (inputs, mappings) {
+ return inputs.filter(function (input) {
+ if (input.required && !mappings[input.name]) {
+ return input;
+ }
+ });
+}
+
+ /**
+ * Validate that the incoming data has the fields expected
+ * in the mappings
+ * @access private
+ */
+function validateData (data, mappings) {
+ var missingInputs = [];
+ if (!data.features || !Array.isArray(data.features)) {
+ throw new Error('Data is expected to have features array!');
+ }
+ var firstRow = data.features[0].attributes;
+ for (var key in mappings) {
+ if (mappings.hasOwnProperty(key)) {
+ var fld = getMappingFieldName(key, mappings[key].field);
+ if (!firstRow.hasOwnProperty(fld)) {
+ missingInputs.push(fld);
+ }
+ }
+ }
+ return missingInputs;
+}
+
+ /**
+ * TODO does nothing, must figure out.
+ * Centralize and abstract the computation of
+ * expected field names, based on the mapping name
+ * @access private
+ */
+function getMappingFieldName (mappingName, fieldName) {
+ // this function why?
+
+ var name = fieldName;
+ // if(mappingName.toLowerCase() === 'count'){
+ // name = fieldName + '_SUM';
+ // }
+ return name;
+}
+
+var utils = {
+ mixin: mixin,
+ supplant: supplant,
+ mergeRecursive: mergeRecursive,
+ getTokenValue: getTokenValue,
+ validateMappings: validateMappings,
+ validateData: validateData,
+ getMappingFieldName: getMappingFieldName
+};
+
+/**
+ * Return a default definition Object
+ * @return {Object} Default definition
+ */
+function defaultDefinition () {
+ return {
+ dataset: {
+ query: defaultQuery()
+ },
+ template: {}
+ };
+}
+
+/**
+ * Return AGO query defaults
+ * @return {Object} Default query
+ */
+function defaultQuery () {
+ return {
+ where: '1=1',
+ returnGeometry: false,
+ returnDistinctValues: false,
+ returnIdsOnly: false,
+ returnCountOnly: false,
+ outFields: '*',
+ sqlFormat: 'standard',
+ f: 'json'
+ };
+}
+
+/**
+ * Ensure that all required inputs exist in mappings
+ * @param {object} mappings Mappings object
+ * @param {array} inputs Array of inputs in specification
+ * @return {object} Returns mappings
+ */
+function applyDefaultsToMappings (mappings, inputs) {
+ var errs = [];
+ // iterate over inputs
+ for (var i = 0; i < inputs.length; i++) {
+ var input = inputs[i];
+
+ // If required but not there
+ if (input.required && !mappings[input.name]) {
+ errs.push(input.name);
+ }
+
+ // if it's not required, has a default and not in the mappings
+ if (!input.required && !mappings[input.name] && input['default']) {
+ // add the default
+ mappings[input.name] = input['default'];
+ }
+ }
+ if (errs.length > 0) {
+ throw new Error(("Required Mappings Missing: " + (errs.join(','))));
+ } else {
+ return mappings;
+ }
+}
+
+var specUtils = {
+ defaultDefinition: defaultDefinition,
+ defaultQuery: defaultQuery,
+ applyDefaultsToMappings: applyDefaultsToMappings
+};
+
+/**
+ * Takes in params, iterates over them, encodes and returns stringified and encoded query
+ *
+ * @param {object} params - merged default and user defined parameters
+ *
+ * @returns {string} - stringified and encoded query
+ */
+function serializeQueryParams (params) {
+ var str = [];
+ for (var param in params) {
+ if (params.hasOwnProperty(param)) {
+ var val = params[param];
+ if (typeof val !== 'string') {
+ val = JSON.stringify(val);
+ }
+ str.push(((encodeURIComponent(param)) + "=" + (encodeURIComponent(val))));
+ }
+ }
+ var queryString = str.join('&');
+ return queryString;
+}
+
+/**
+ * Helper function to request JSON from a url
+ * @param {string} url URL to request from
+ * @param {Function} callback Callback function
+ * @param {number} timeout Timeout on request
+ * @return {object} Response object
+ */
+function getJson$1 (url, callback, timeout) {
+ var cb = function (err, data) {
+ // if timeout error then return a timeout error
+ if (err && err.response === '') {
+ callback(new Error('This service is taking too long to respond, unable to chart'));
+ } else if (err) {
+ // Other errors return generic error.
+ callback(new Error(("Error loading " + url + " with a response of: " + (err.message))));
+ } else {
+ callback(null, JSON.parse(data.responseText));
+ }
+ };
+ if (url.length > 2000) {
+ var uri = url.split('?');
+ d3.xhr(uri[0])
+ .on('beforesend', function (xhr$$1) { xhr$$1.timeout = timeout; xhr$$1.ontimeout = xhr$$1.onload; })
+ .header('Content-Type', 'application/x-www-form-urlencoded')
+ .post(uri[1], cb);
+ } else {
+ d3.xhr(url)
+ .on('beforesend', function (xhr$$1) { xhr$$1.timeout = timeout; xhr$$1.ontimeout = xhr$$1.onload; })
+ .get(cb);
+ }
+}
+
+/**
+ * Given a dataset hash create a feature service request
+ * @param {object} dataset Dataset object
+ * @param {object} queryFromSpec Query passed in by the user
+ * @return {string} url string
+ */
+function createFeatureServiceRequest (dataset, queryFromSpec) {
+ var mergedQuery = mixin({}, defaultQuery(), queryFromSpec);
+
+ // Handle bbox
+ if (mergedQuery.bbox) {
+ // make sure a geometry was not also passed in
+ if (mergedQuery.geometry) {
+ throw new Error('Dataset.query can not have both a geometry and a bbox specified');
+ }
+ // Get the bbox (w,s,e,n)
+ var bboxArr = mergedQuery.bbox.split(',');
+
+ // Remove it so it's not serialized as-is
+ delete mergedQuery.bbox;
+
+ // cook it into a json string
+ mergedQuery.geometry = JSON.stringify({
+ xmin: bboxArr[0],
+ ymin: bboxArr[2],
+ xmax: bboxArr[1],
+ ymax: bboxArr[3]
+ });
+ // set spatial ref as geographic
+ mergedQuery.inSR = '4326';
+ }
+
+ if (!mergedQuery.groupByFieldsForStatistics && !!dataset.mappings.group) {
+ mergedQuery.groupByFieldsForStatistics = dataset.mappings.group.field;
+ }
+ if (!mergedQuery.outStatistics && !!dataset.mappings.count) {
+ // TODO Why are we explicitlystating _SUM as a stats type?
+ mergedQuery.orderByFields = (dataset.mappings.count.field) + "_SUM";
+ mergedQuery.outStatistics = JSON.stringify([{
+ statisticType: 'sum',
+ onStatisticField: dataset.mappings.count.field,
+ outStatisticFieldName: ((dataset.mappings.count.field) + "_SUM")
+ }]);
+ }
+
+ // iterate the mappings keys to check for sort
+ // -----------------------------------------------------------------
+ // This approach would seem 'clean' but if there are multiple fields
+ // to sort by, the order would be determined by how javascript decides to
+ // iterate the mappings property hash.
+ // Thus, using mappings.sort gives the developer explicit control
+ // -----------------------------------------------------------------
+ // var sort = [];
+ // for (var property in dataset.mappings) {
+ // if (dataset.mappings.hasOwnProperty(property)) {
+ // if(dataset.mappings[property].sort){
+ // //ok - build up the sort
+ // sort.push(dataset.mappings[property].field + ' ' + dataset.mappings[property].sort);
+ // }
+ // }
+ // }
+ // if(sort.length > 0){
+ // mergedQuery.orderByFields = sort.join(',');
+ // }
+ // -----------------------------------------------------------------
+ // check for a sort passed directly in
+
+ if (dataset.mappings.sort) {
+ mergedQuery.orderByFields = dataset.mappings.sort;
+ }
+
+ var url = (dataset.url) + "/query?" + (serializeQueryParams(mergedQuery));
+
+ if (dataset.token) {
+ url = url + "&token=" + (dataset.token);
+ }
+
+ return url;
+}
+
+var requestUtils = {
+ getJson: getJson$1,
+ createFeatureServiceRequest: createFeatureServiceRequest
+};
+
+// import specTemplates from './charts/specs';
+// get cedar root URL for loading chart specs
+var baseUrl = (function () {
+ var cdnProtocol = 'http:';
+ var cdnUrl = '//esri.github.io/cedar/js';
+ var src;
+ if (window && window.document) {
+ src = (window.document.currentScript && window.document.currentScript.src);
+ if (src) {
+ // real browser, get base url from current script
+ return src.substr(0, src.lastIndexOf('/'));
+ } else {
+ // ie, set base url to CDN
+ // NOTE: could fallback to CDN only if can't find any scripts named cedar
+ return (window.document.location ? window.document.location.protocol : cdnProtocol) + cdnUrl;
+ }
+ } else {
+ // node, set base url to CDN
+ return cdnProtocol + cdnUrl;
+ }
+})();
+
+var Cedar = function Cedar (options) {
+ var this$1 = this;
+
+ this.version = version;
+ // Pull templates in
+ // this.chartTypes = specTemplates;
+
+ var opts = options || {};
+
+ var spec;
+
+ this.baseUrl = baseUrl;
+ this.chartTypes = ['bar', 'bar-horizontal', 'bubble', 'grouped', 'pie', 'scatter', 'sparkline', 'time', 'time-trendline'];
+
+ // Cedar configs such as size..
+ this.width = undefined;
+ this.height = undefined;
+ this.autolabels = true;
+ this.maxLabelLength = undefined;
+
+ // Array to hold event handlers
+ this._events = [];
+
+ // initialize internal definition
+ this._definition = specUtils.defaultDefinition();
+
+ // initialize vega view aka chart
+ this._view = undefined;
+
+ // the vega tooltip
+ this._tooltip = undefined;
+
+ // transform function
+ this._transform = undefined;
+
+ // Queue to hold methods called while xhrs are in progress
+ this._methodQueue = [];
+
+ // Set a base timeout
+ this._timeout = undefined;
+
+ // override the base timeout
+ if (opts.timeout) {
+ this._timeout = opts.timeout;
+ }
+
+ // override the base url
+ if (opts.baseUrl) {
+ this.baseUrl = opts.baseUrl;
+ }
+
+ /**
+ * Flag used to determine if the library is waiting for an xhr to return.
+ * @access private
+ */
+ this._pendingXhr = false;
+
+ /**
+ * Definition
+ */
+
+ if (opts.definition) {
+ if (typeof opts.definition === 'object') {
+ // hold onto the definition
+ this._definition = opts.definition;
+ } else if (typeof opts.definition === 'string') {
+ // assume it's a url (relative or absolute) and fetch the def object
+ this._pendingXhr = true;
+ requestUtils.getJson(opts.definition, function (err, data) {
+ if (err) {
+ throw new Error('Error fetching definition object', err);
+ }
+ this$1._pendingXhr = false;
+ this$1._definition = data;
+ this$1._purgeMethodQueue();
+ }, this._timeout);
+ } else {
+ throw new Error('parameter definition must be an object or string (url)');
+ }
+ }
+
+ // if there are overrides
+ if (opts.override) {
+ this._definition.override = opts.override;
+ }
+
+ /**
+ * Specs
+ */
+
+ // first, check for pre-defined chart type passed in as 'type'
+ spec = this._getSpecificationUrl(opts.type);
+
+ // If url or object passed use that...
+ if (opts.specification) {
+ spec = opts.specification;
+ }
+
+ if (spec) {
+ // is it an object or string, assumed to be url
+ if (typeof spec === 'object') {
+ // hold onto the template
+ this._definition.specification = spec;
+ } else if (typeof spec === 'string') {
+ // assume it's a url (rel or abs) and fetch the template object
+ this._pendingXhr = true;
+ this._pendingXhr = true;
+ requestUtils.getJson(spec, function (err, data) {
+ if (err) {
+ throw new Error('Error fetching template object', err);
+ }
+ this$1._pendingXhr = false;
+ this$1._definition.specification = data;
+ this$1._purgeMethodQueue();
+ }, this._timeout);
+ } else {
+ throw new Error('parameter specification must be an object or string (url)');
+ }
+ }
+
+ // Allow a dataset to be passed in....
+ if (opts.dataset && typeof opts.dataset === 'object') {
+ opts.dataset.query = utils.mixin({}, specUtils.defaultQuery(), opts.dataset.query);
+ // Assign it
+ this._definition.dataset = opts.dataset;
+ }
+
+ /**
+ * Tooltip
+ */
+ // allow a tooltip to be passed in...
+ if (opts.tooltip && typeof opts.tooltip === 'object') {
+ this.tooltip = opts.tooltip;
+ } else {
+ // Build a default tooltip based on first two imputs....
+ var inputs = [];
+ for (var input in this._definition.dataset.mappings) {
+ if (this$1._definition.dataset.mappings.hasOwnProperty(input)) {
+ var field = this$1._definition.dataset.mappings[input].field;
+ if (field !== undefined && field !== null) {
+ inputs.push(field);
+ }
+ }
+ }
+ if (inputs.length >= 2) {
+ this.tooltip = {
+ 'title': ("{" + (inputs[0]) + "}"),
+ 'content': ("{" + (inputs[1]) + "}")
+ };
+ }
+ }
+
+ /**
+ * tranform
+ */
+ // Allow a transform func to pass in
+ if (opts.transform && typeof opts.transform === 'function') {
+ this._transform = opts.transform;
+ }
+};
+
+var prototypeAccessors = { dataset: {},specification: {},override: {},tooltip: {},transform: {} };
+
+/**
+ * Properties
+ */
+// Datasets
+prototypeAccessors.dataset.get = function () {
+ return this._definition.dataset;
+};
+prototypeAccessors.dataset.set = function (val) {
+ this._definition.dataset = val;
+};
+
+// Specification
+prototypeAccessors.specification.get = function () {
+ return this._definition.specification;
+};
+prototypeAccessors.specification.set = function (val) {
+ this._definition.specification = val;
+};
+
+// override
+prototypeAccessors.override.get = function () {
+ return this._definition.override;
+};
+prototypeAccessors.override.set = function (val) {
+ this._definition.override = val;
+ // return this.update(); // TODO is this the best way?
+};
+
+// Tooltip
+prototypeAccessors.tooltip.get = function () {
+ return this._definition.tooltip;
+};
+prototypeAccessors.tooltip.set = function (val) {
+ this._definition.tooltip = val;
+ if (this._definition.tooltip.id === undefined || this._definition.tooltip.id === null) {
+ this._definition.tooltip.id = "cedar-" + (Date.now());
+ }
+};
+
+// transform
+prototypeAccessors.transform.get = function () {
+ return this._transform;
+};
+prototypeAccessors.transform.set = function (val) {
+ this._transform = val;
+};
+
+Cedar.prototype._getSpecificationUrl = function _getSpecificationUrl (spec) {
+ if (this.chartTypes.indexOf(spec) !== -1) {
+ spec = (this.baseUrl) + "/charts/" + (this.chartTypes[this.chartTypes.indexOf(spec)]) + ".json";
+ }
+ return spec;
+};
+
+/**
+ * Inspect the current state of the Object
+ * and determine if we have sufficient information
+ * to render the chart
+ * @return {object} Hash of the draw state + any missing requirements
+ */
+Cedar.prototype.canDraw = function canDraw () {
+ // dataset?
+ // dataset.url || dataset.data?
+ // dataset.mappings?
+ // specification?
+ // specification.template?
+ // specification.inputs?
+ // specification.inputs ~ dataset.mappings?
+
+ return {drawable: true, errs: []};
+};
+
+/**
+ * Draw the chart into the DOM element
+ *
+ * @example
+ *
+ * var chart = new Cedar({
+ * "type": "scatter",
+ * "dataset":{
+ * "url":"http://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Education_WebMercator/MapServer/5",
+ * "query":{},
+ * "mappings":{
+ * "x": {"field":"POPULATION_ENROLLED_2008","label":"Enrolment 2008"},
+ * "y": {"field":"SQUARE_FOOTAGE","label":"Square Footage"},
+ * "color":{"field":"FACUSE","label":"Facility Type"}
+ * }
+ * }
+ * });
+ *
+ * chart.show({
+ * elementId: "#chart"
+ * });
+ *
+ * @param{object} options
+ * @param {String} options.elementId [required] Id of the Dom element into which the chart will be rendered
+ * @param {String} options.renderer "canvas" or "svg" (default: `svg`)
+ * @param {Boolean} options.autolabels place axis labels outside any tick labels (default: false)
+ * @param {String} options.token Token to be used if the data or spec are on a secured server
+ */
+Cedar.prototype.show = function show (options, clb) {
+ if (this._pendingXhr) {
+ // TODO addToMethodQueue
+ this._addToMethodQueue('show', [options, clb]);
+ } else {
+ var err;
+ // ensure we got an elementId
+ if (!options.elementId) {
+ err = 'Cedar.show requires options.elementId';
+ }
+ // Check if element exists in the page
+ if (d3.select(options.elementId)[0][0] === null) {
+ err = "Element " + (options.elementId) + " is not present in the DOM";
+ }
+
+ // hold onto the id
+ this._elementId = options.elementId;
+ this._renderer = options.renderer || 'svg'; // default to svg
+ this.width = options.width || this.height;
+ this.height = options.height || this.height;
+ if (options.autolabels !== undefined && options.autolabels !== null) {
+ this.autolabels = options.autolabels;
+ }
+
+ if (options.maxLabelLength) {
+ // check if truncate label length has been passed in
+ this.maxLabelLength = options.maxLabelLength;
+ }
+
+ // hold onto the token
+ if (options.token) {
+ this._token = options.token;
+ }
+
+ if (err) {
+ throw new Error(err);
+ }
+
+ var chk = this.canDraw();
+
+ if (chk.drawable) {
+ this.update(clb);
+ } else {
+ // report the issues
+ var errs = chk.issues.join(',');
+ throw new Error(("Chart can not be drawn because: " + errs));
+ }
+ }
+};
+
+/**
+ * Draw the chart based on any changes to data or specifications
+ * Should be called after a user modifies
+ * the dataset, query, mappings, chart specification or element size
+ *
+ * @example
+ * dataset = {"url": "...", "mappings": {"x": {"field": "STATE"}, "y": {"field": "POPULATION"}}};
+ * chart = new Cedar({ "type": "bar", "dataset": dataset });
+ * chart.show({elementId: "#chart"});
+ * chart.dataset.query.where = "POPULATION>30000";
+ * chart.update();
+ */
+Cedar.prototype.update = function update (clb) {
+ var this$1 = this;
+
+ if (this._view) {
+ this.emit('update-start');
+ }
+
+ if (this._pendingXhr) {
+ this._addToMethodQueue('update');
+ } else {
+ if (this._view) {
+ // remove handlers
+ // TODO Remove existing handlers
+ this._remove(this._view);
+ }
+
+ try {
+ // Creates the HTML Div and styling if not already created
+ if (this._definition.tooltip) {
+ this._createTooltip(this._definition.tooltip.id);
+ }
+
+ // Ensure we have required inputs or defaults
+ var compiledMappings = specUtils.applyDefaultsToMappings(this._definition.dataset.mappings, this._definition.specification.inputs);
+
+ var queryFromSpec = utils.mixin({}, this._definition.specification.query, this._definition.dataset.query);
+ queryFromSpec = JSON.parse(utils.supplant(JSON.stringify(queryFromSpec), compiledMappings));
+
+ // allow binding to query properties
+ compiledMappings.query = queryFromSpec;
+
+ // compile the template + mappings --> vega spec
+ var spec = JSON.parse(utils.supplant(JSON.stringify(this._definition.specification.template), compiledMappings));
+
+ // merge in user specified style overrides
+ spec = utils.mergeRecursive(spec, this._definition.override);
+
+ // if the spec has a url in the data node, delete it TODO: need to readress this.
+ if (spec.data[0].url) {
+ delete spec.data[0].url;
+ }
+
+ if (this._definition.dataset.data) {
+ // create the data node using the passed in data
+ spec.data[0].values = this._definition.dataset.data; // TODO: only works on first spec, need to address for multiple datasets.
+
+ // Send to vega
+ this._renderSpec(spec, clb);
+ } else {
+ // We need to fetch the data so....
+ var url = requestUtils.createFeatureServiceRequest(this._definition.dataset, queryFromSpec);
+
+ // create a callback closure to carry the spec
+ var cb = function (err, data) {
+ // Normalize error response
+ if (!err && !!data.error) {
+ err = new Error(data.error.message || data.error.details[0]);
+ }
+ // if no errors then continue...
+ if (!err) {
+ if (this$1._transform && typeof this$1._transform === 'function') {
+ data = this$1._transform(data, this$1._definition.dataset);
+ }
+ // TODO add error handlers for xhr and AGS errors.
+ spec.data[0].values = data;
+ // send to vega
+ this$1._renderSpec(spec, clb);
+ } else {
+ // optional callback
+ if (!!clb && typeof clb === 'function') {
+ clb(err, data);
+ }
+ }
+ };
+
+ // fetch the data from the service
+ requestUtils.getJson(url, cb, this._timeout);
+ }
+ } catch (ex) {
+ throw (ex);
+ }
+ }
+};
+
+/**
+ * RENDER CHART FUNCTIONS
+ *
+ *
+ * Render a compiled Vega specification using vega runtime
+ */
+
+Cedar.prototype._renderSpec = function _renderSpec (spec, clb) {
+ var this$1 = this;
+
+ if (this.autolabels === true) {
+ spec = this._placeLabels(spec);
+ spec = this._placeaAxisTicks(spec);
+ }
+ // Use vega to parse the spec
+ // It will handle the spec as an object or url
+ vg.parse.spec(spec, function (err, chartCtor) {
+ // create the view
+ this$1._view = chartCtor({
+ el: this$1._elementId,
+ renderer: this$1._renderer
+ });
+
+ var width = this$1.width || parseInt(d3.select(this$1._elementId).style('width'), 10) || 500;
+ var height = this$1.height || parseInt(d3.select(this$1._elementId).style('height'), 10) || 500;
+
+ // render into the element
+ this$1._view.width(width).height(height).update();
+
+ // attach event proxies
+ this$1._attach(this$1._view);
+
+ if (this$1._view) {
+ this$1.emit('update-end');
+ }
+
+ // expose errors
+ if (!!clb && typeof clb === 'function') {
+ clb(err, spec);
+ }
+ });
+};
+
+/**
+ * AXIS TICK FUNCTIONS START HERE
+ *
+ *
+ * Automatically determines axis title placement
+ *
+ * Calculates the maximum length of a tick label and adds padding
+ */
+
+Cedar.prototype._placeLabels = function _placeLabels (spec) {
+ var this$1 = this;
+
+ try {
+ var fields = {};
+ var lengths = {};
+ var inputs = [];
+ // Get all inputs that may be axes
+ for (var input in this._definition.dataset.mappings) {
+ // check also if property is not inherited from prototype
+ if (this$1._definition.dataset.mappings.hasOwnProperty(input)) {
+ var field = this$1._definition.dataset.mappings[input].field;
+ if (field) {
+ inputs.push(input);
+ fields[input] = field;
+ lengths[input] = 0;
+ }
+ }
+ }
+ var length = 0;
+
+ // find the max length value for each axis
+ spec.data[0].values.features.forEach(function (feature) {
+ inputs.forEach(function (axis) {
+ length = (feature.attributes[fields[axis]] || '').toString().length;
+ if (this$1.maxLabelLength) {
+ // Need to make sure that the gap between title and labels isn't ridiculous
+ length = length < (this$1.maxLabelLength + 1) ? length : this$1.maxLabelLength;
+ }
+ if (length > lengths[axis]) {
+ lengths[axis] = length;
+ }
+ });
+ });
+
+ // Change each axis title offset based on longest value
+ inputs.forEach(function (axis, index) {
+ var angle = 0;
+ if (!!spec.axes && !!spec.axes[index]) {
+ if (spec.axes[index].properties.labels.angle) {
+ angle = spec.axes[index].properties.labels.angle.value;
+ }
+ if (spec.axes[index].type === 'y') {
+ angle = 100 - angle;
+ }
+ if (this$1.maxLabelLength) {
+ // Set max length of axes titles
+ spec.axes[index].properties.labels.text = {'template': ("{{ datum.data | truncate:\"" + (this$1.maxLabelLength) + "\"}}")};
+ }
+ // set title offset
+ spec.axes[index].titleOffset = Math.abs(lengths[axis] * angle / 100 * 8) + 35;
+ }
+ });
+ return spec;
+ } catch (ex) {
+ throw (ex);
+ }
+};
+
+/**
+ * Automatically determines number of axis tick marks
+ *
+ * Calculates the maximum length of a tick label and adds padding
+ * TODO: remove expectation that there are both x,y axes
+ */
+
+Cedar.prototype._placeaAxisTicks = function _placeaAxisTicks (spec) {
+ if (spec.axes) {
+ try {
+ var width = this.width || parseInt(d3.select(this._elementId).style('width'), 10) || 500;
+ var height = this.height || parseInt(d3.select(this._elementId).style('height'), 10) || 500;
+
+ spec.axes[0].ticks = width / 100;
+ if (spec.axes[1]) {
+ spec.axes[1].ticks = height / 30;
+ }
+ } catch (ex) {
+ throw (ex);
+ }
+ }
+ return spec;
+};
+
+/**
+ * TOOLTIP LOGIC HERE
+ *
+ * Instantiates the tooltip element and styling
+ * @access private
+ */
+Cedar.prototype._createTooltip = function _createTooltip (elem) {
+ var this$1 = this;
+
+ var tooltipDiv = document.getElementById(elem);
+
+ // Check if tooltip has been created or not...
+ if (tooltipDiv) {
+ return tooltipDiv;
+ }
+
+ // TODO: remove inline CSS
+ var style = document.createElement('style');
+ style.type = 'text/css';
+ style.innerHTML = '.cedar-tooltip {background-color: white; padding: 3px 10px; color: #333; margin: -30px 0 0 20px; position: absolute; z-index: 2000; font-size: 10px; border: 1px solid #BBB;} .cedar-tooltip .title {font-size: 13pt; font-weight: bold; } .cedar-tooltip .content {font-size: 10pt; } ';
+ document.getElementsByTagName('head')[0].appendChild(style);
+
+ tooltipDiv = document.createElement('div');
+ tooltipDiv.className = 'cedar-tooltip';
+ tooltipDiv.id = elem;
+ tooltipDiv.cssText = 'display: none';
+ // We need tooltip at the top of the page
+ document.body.insertBefore(tooltipDiv, document.body.firstChild);
+
+ this.on('mouseout', function (event, data) {
+ this$1._updateTooltip(event, null);
+ });
+ this.on('mousemove', function (event, data) {
+ this$1._updateTooltip(event, data);
+ });
+ return tooltipDiv;
+};
+
+/**
+ * Places the tooltipe and fills in content
+ *
+ * @access private
+ */
+Cedar.prototype._updateTooltip = function _updateTooltip (event, data) {
+ var cedartip = document.getElementById(this._definition.tooltip.id);
+ if (!data) {
+ cedartip.style.display = 'none';
+ return;
+ }
+ cedartip.style.top = (event.pageY) + "px";
+ cedartip.style.left = (event.pageX) + "px";
+ cedartip.style.display = 'block';
+
+ var content = "" + (this._definition.tooltip.title) + "
";
+ content += "
" + (this._definition.tooltip.content) + "
"; + + cedartip.innerHTML = content.replace(/\{(\w+)\}/g, function (match, $1) { + return data[$1]; + }); +}; + + /** + * EVENT LOGIC HERE + * + * + * Add a handler for the named event. + * Events: + *- mouseover + *- mouseout + *- click + *- update-start + *- update-end + * + * + * + * Callback from Cedar events + *- callback Cedar~eventCallback + *- param {Object} event - event response such as mouse location + *- param {Object} data - chart data object + * + * @example + * var chart = new Cedar({ ... }); + * chart.on('mouseover', function(event, data) { + * console.log("Mouse Location:", [event.offsetX, event.offsetY]); + * console.log("Data value:", data[Object.keys(data)[0]]); + * }); + * + * @param {String} eventName name of the event that invokes callback + * @param {Cedar~eventCallback} callback - The callback that handles the event. + */ +Cedar.prototype.on = function on (evtName, callback) { + this._events.push({type: evtName, callback: callback}); +}; +/** + * Remove a hanlder for the named event + */ +Cedar.prototype.off = function off (evtName, callback) { + this._events.forEach(function (registeredEvent, index, object) { + if (registeredEvent.type === evtName && registeredEvent.callback === callback) { + object.splice(index, 1); + } + }); +}; + +/** + * Trigger a callback + * @param {string} eventName - ["mouseover","mouseout","click","update-start","update-end"] + */ +Cedar.prototype.emit = function emit (eventName) { + if (!!this._view._handler._handlers[ eventName ] && !!this._view._handler._handlers[ eventName ][0]) { + this._view._handler._handlers[ eventName ][0].handler(); + } +}; + +/** + * Attach the generic proxy hanlders to the chart view + * @access private + */ + Cedar.prototype._attach = function _attach (view) { + view.on('mouseover', this._handler('mouseover')); + view.on('mouseout', this._handler('mouseout')); + view.on('mousemove', this._handler('mousemove')); + view.on('click', this._handler('click')); + view.on('update-start', this._handler('update-start')); + view.on('update-end', this._handler('update-end')); +}; + +/** + * Remove all event handlers from the view + * @access private + */ +Cedar.prototype._remove = function _remove (view) { + view.off('mouseover'); + view.off('mouseout'); + view.off('mousemove'); + view.off('click'); + view.off('update-start'); + view.off('update-end'); +}; + +/** + * Creates an entry in the method queue, executed + * once a pending xhr is completed + * @access private + */ +Cedar.prototype._addToMethodQueue = function _addToMethodQueue (name$$1, args) { + this._methodQueue.push({ method: name$$1, args: args }); +}; + +/** + * empties the method queue by calling the queued methods + * This helps build a more syncronous api, while still + * doing async things in the code + * @access private + */ +Cedar.prototype._purgeMethodQueue = function _purgeMethodQueue () { + var this$1 = this; + + if (this._methodQueue.length > 0) { + this._methodQueue.forEach(function (action, index) { + this$1[action.method].apply(this$1, action.args); + }); + } +}; + +/** + * Generic event handler proxy + * @access private + */ +Cedar.prototype._handler = function _handler (evtName) { + var this$1 = this; + + // return a handler function w/ the events hash closed over + var handler = function (evt, item) { + this$1._events.forEach(function (registeredHandler) { + if (registeredHandler.type === evtName) { + // invoke the callback with the data + if (item) { + registeredHandler.callback(evt, item.datum.attributes); + } else { + registeredHandler.callback(evt, null); + } + } + }); + }; + return handler; +}; + +/** + * SELECT LOGIC STARTS HERE + * + * Highlight marker based on attribute value + * + * @example + * chart = new Cedar({...}); + * chart.select({key: 'ZIP_CODE', value: '20002'}); + * + * @param {object} options - Object(key, value) to match. Calls hover on work + * @returns {Array} items - array of chart objects that match the criteria + */ + +Cedar.prototype.select = function select (options) { + var this$1 = this; + + var view = this._view; + var items = view.model().scene().items[0].items[0].items; + + items.forEach(function (item) { + if (item.datum.attributes[options.key] === options.value) { + if (item.hasPropertySet('hover')) { + this$1._view.update({props: 'hover', items: item}); + } + } + }); + + return items; +}; + + /** + * Removes highlighted chart items + * + * If "options" are used, only clear specific items, otherwise clears all highlights. + * @param {Object} options - Object(key, value) to match. Calls hover on mark + * @returns {Array} items - array of chart objects that match the criteria, or null if all items. + */ + +Cedar.prototype.clearSelection = function clearSelection (options) { + var this$1 = this; + + var view = this._view; + + if (!!options && !!options.key) { + var items = view.model().scene().items[0].items[0].items; + items.forEach(function (item) { + if (item.datum.attributes[options.key] === options.value) { + this$1._view.update({props: 'update', items: item}); + } + }); + return items; + } else { + // clear all + this._view.update(); + return null; + } +}; + +Cedar.getJson = function getJson (url, callback, timeout) { + return requestUtils.getJson(url, callback, timeout); +}; + +/** + * Other now exposed utils! + */ +Cedar._validateMappings = function _validateMappings (inputs, mappings) { + return utils.validateMappings(inputs, mappings); +}; +Cedar._validateData = function _validateData (data, mappings) { + return utils.validateData(data, mappings); +}; +Cedar._createFeatureServiceRequest = function _createFeatureServiceRequest (dataset, queryFromSpec) { + return requestUtils.createFeatureServiceRequest(dataset, queryFromSpec); +}; +Cedar._getMappingFieldName = function _getMappingFieldName (mappingName, fieldName) { + return utils.getMappingFieldName(mappingName, fieldName); +}; + +Object.defineProperties( Cedar.prototype, prototypeAccessors ); + +return Cedar; + +}))); +//# sourceMappingURL=cedar.js.map diff --git a/dist/cedar.js.map b/dist/cedar.js.map new file mode 100644 index 00000000..4843ecb2 --- /dev/null +++ b/dist/cedar.js.map @@ -0,0 +1 @@ +{"version":3,"file":null,"sources":["../src/utils/utils.js","../src/utils/spec.js","../src/utils/request.js","../src/cedar.js"],"sourcesContent":["import * as d3 from 'd3';\n/**\n * Merges n objects\n * @param {object} source Empty object that other objects will be merged into\n * @return {Object} Merged objects\n */\nexport function mixin (source) {\n const args = [...arguments];\n for (let i = 1; i < args.length; i++) {\n d3.entries(args[i]).forEach((p) => {\n source[p.key] = p.value;\n });\n }\n return source;\n}\n\n/**\n * Recursively merge properties of two objects\n */\nexport function mergeRecursive (obj1, obj2) {\n for (let p in obj2) {\n if (obj2.hasOwnProperty(p)) {\n try {\n // Property in destination object set; update its value.\n if (obj2[p].constructor === Object || obj2[p].constructor === Array) {\n obj1[p] = mergeRecursive(obj1[p], obj2[p]);\n } else {\n obj1[p] = obj2[p];\n }\n } catch (e) {\n // Property in destination object not set; create it and set its value\n obj1[p] = obj2[p];\n }\n }\n }\n return obj1;\n}\n\n/**\n * Token replacement on a string\n * @param {string} template string template\n * @param {object} params Object hash that maps to the tokens to be replaced\n * @return {string} string with values replaced\n */\nexport function supplant (template, params) {\n const t = template.replace(/{([^{}]*)}/g,\n (a, b) => {\n const r = getTokenValue(params, b);\n\n return typeof r === 'string' || typeof r === 'number' ? r : a;\n }\n );\n return t.replace(/\"{([^{}]*)}\"/g,\n (a, b) => {\n let r = getTokenValue(params, b);\n return (!!r && r.constructor === Array) ? JSON.stringify(r) : a;\n });\n}\n\n/**\n * Get the value of a token from a hash\n * @param {object} tokens Hash {a: 'a', b: { c: 'c'} }\n * @param {string} tokenName Property name: 'a' would yield 'a', 'b.c' would yield 'c'\n * @return {Any} Returns value contained within property\n * Pulled from gulp-token-replace (MIT license)\n * https://github.com/Pictela/gulp-token-replace/blob/master/index.js\n */\nexport function getTokenValue (tokens, tokenName) {\n let tmpTokens = tokens;\n let tokenNameParts = tokenName.split('.');\n for (let i = 0; i < tokenNameParts.length; i++) {\n if (tmpTokens.hasOwnProperty(tokenNameParts[i])) {\n tmpTokens = tmpTokens[tokenNameParts[i]];\n } else {\n return null;\n }\n }\n return tmpTokens;\n}\n\n /**\n * Helper function that validates that the\n * mappings hash contains values for all\n * the inputs\n * @param {array} inputs Array of inputs\n * @param {object} mappings Hash of mappings\n * @return {array} Missing mappings\n * @access private\n */\nexport function validateMappings (inputs, mappings) {\n return inputs.filter((input) => {\n if (input.required && !mappings[input.name]) {\n return input;\n }\n });\n}\n\n /**\n * Validate that the incoming data has the fields expected\n * in the mappings\n * @access private\n */\nexport function validateData (data, mappings) {\n const missingInputs = [];\n if (!data.features || !Array.isArray(data.features)) {\n throw new Error('Data is expected to have features array!');\n }\n const firstRow = data.features[0].attributes;\n for (let key in mappings) {\n if (mappings.hasOwnProperty(key)) {\n let fld = getMappingFieldName(key, mappings[key].field);\n if (!firstRow.hasOwnProperty(fld)) {\n missingInputs.push(fld);\n }\n }\n }\n return missingInputs;\n}\n\n /**\n * TODO does nothing, must figure out.\n * Centralize and abstract the computation of\n * expected field names, based on the mapping name\n * @access private\n */\nexport function getMappingFieldName (mappingName, fieldName) {\n // this function why?\n\n let name = fieldName;\n // if(mappingName.toLowerCase() === 'count'){\n // name = fieldName + '_SUM';\n // }\n return name;\n}\n\nconst utils = {\n mixin,\n supplant,\n mergeRecursive,\n getTokenValue,\n validateMappings,\n validateData,\n getMappingFieldName\n};\n\nexport default utils;\n","/**\n * Return a default definition Object\n * @return {Object} Default definition\n */\nexport function defaultDefinition () {\n return {\n dataset: {\n query: defaultQuery()\n },\n template: {}\n };\n}\n\n/**\n * Return AGO query defaults\n * @return {Object} Default query\n */\nexport function defaultQuery () {\n return {\n where: '1=1',\n returnGeometry: false,\n returnDistinctValues: false,\n returnIdsOnly: false,\n returnCountOnly: false,\n outFields: '*',\n sqlFormat: 'standard',\n f: 'json'\n };\n}\n\n/**\n * Ensure that all required inputs exist in mappings\n * @param {object} mappings Mappings object\n * @param {array} inputs Array of inputs in specification\n * @return {object} Returns mappings\n */\nexport function applyDefaultsToMappings (mappings, inputs) {\n const errs = [];\n // iterate over inputs\n for (let i = 0; i < inputs.length; i++) {\n const input = inputs[i];\n\n // If required but not there\n if (input.required && !mappings[input.name]) {\n errs.push(input.name);\n }\n\n // if it's not required, has a default and not in the mappings\n if (!input.required && !mappings[input.name] && input['default']) {\n // add the default\n mappings[input.name] = input['default'];\n }\n }\n if (errs.length > 0) {\n throw new Error(`Required Mappings Missing: ${errs.join(',')}`);\n } else {\n return mappings;\n }\n}\n\nconst specUtils = {\n defaultDefinition,\n defaultQuery,\n applyDefaultsToMappings\n};\n\nexport default specUtils;\n","import * as d3 from 'd3';\nimport { mixin } from './utils';\nimport { defaultQuery } from './spec';\n\n/**\n * Takes in params, iterates over them, encodes and returns stringified and encoded query\n *\n * @param {object} params - merged default and user defined parameters\n *\n * @returns {string} - stringified and encoded query\n */\nfunction serializeQueryParams (params) {\n const str = [];\n for (const param in params) {\n if (params.hasOwnProperty(param)) {\n let val = params[param];\n if (typeof val !== 'string') {\n val = JSON.stringify(val);\n }\n str.push(`${encodeURIComponent(param)}=${encodeURIComponent(val)}`);\n }\n }\n const queryString = str.join('&');\n return queryString;\n}\n\n/**\n * Helper function to request JSON from a url\n * @param {string} url URL to request from\n * @param {Function} callback Callback function\n * @param {number} timeout Timeout on request\n * @return {object} Response object\n */\nexport function getJson (url, callback, timeout) {\n const cb = (err, data) => {\n // if timeout error then return a timeout error\n if (err && err.response === '') {\n callback(new Error('This service is taking too long to respond, unable to chart'));\n } else if (err) {\n // Other errors return generic error.\n callback(new Error(`Error loading ${url} with a response of: ${err.message}`));\n } else {\n callback(null, JSON.parse(data.responseText));\n }\n };\n if (url.length > 2000) {\n const uri = url.split('?');\n d3.xhr(uri[0])\n .on('beforesend', (xhr) => { xhr.timeout = timeout; xhr.ontimeout = xhr.onload; })\n .header('Content-Type', 'application/x-www-form-urlencoded')\n .post(uri[1], cb);\n } else {\n d3.xhr(url)\n .on('beforesend', (xhr) => { xhr.timeout = timeout; xhr.ontimeout = xhr.onload; })\n .get(cb);\n }\n}\n\n/**\n * Given a dataset hash create a feature service request\n * @param {object} dataset Dataset object\n * @param {object} queryFromSpec Query passed in by the user\n * @return {string} url string\n */\nexport function createFeatureServiceRequest (dataset, queryFromSpec) {\n const mergedQuery = mixin({}, defaultQuery(), queryFromSpec);\n\n // Handle bbox\n if (mergedQuery.bbox) {\n // make sure a geometry was not also passed in\n if (mergedQuery.geometry) {\n throw new Error('Dataset.query can not have both a geometry and a bbox specified');\n }\n // Get the bbox (w,s,e,n)\n const bboxArr = mergedQuery.bbox.split(',');\n\n // Remove it so it's not serialized as-is\n delete mergedQuery.bbox;\n\n // cook it into a json string\n mergedQuery.geometry = JSON.stringify({\n xmin: bboxArr[0],\n ymin: bboxArr[2],\n xmax: bboxArr[1],\n ymax: bboxArr[3]\n });\n // set spatial ref as geographic\n mergedQuery.inSR = '4326';\n }\n\n if (!mergedQuery.groupByFieldsForStatistics && !!dataset.mappings.group) {\n mergedQuery.groupByFieldsForStatistics = dataset.mappings.group.field;\n }\n if (!mergedQuery.outStatistics && !!dataset.mappings.count) {\n // TODO Why are we explicitlystating _SUM as a stats type?\n mergedQuery.orderByFields = `${dataset.mappings.count.field}_SUM`;\n mergedQuery.outStatistics = JSON.stringify([{\n statisticType: 'sum',\n onStatisticField: dataset.mappings.count.field,\n outStatisticFieldName: `${dataset.mappings.count.field}_SUM`\n }]);\n }\n\n // iterate the mappings keys to check for sort\n // -----------------------------------------------------------------\n // This approach would seem 'clean' but if there are multiple fields\n // to sort by, the order would be determined by how javascript decides to\n // iterate the mappings property hash.\n // Thus, using mappings.sort gives the developer explicit control\n // -----------------------------------------------------------------\n // var sort = [];\n // for (var property in dataset.mappings) {\n // if (dataset.mappings.hasOwnProperty(property)) {\n // if(dataset.mappings[property].sort){\n // //ok - build up the sort\n // sort.push(dataset.mappings[property].field + ' ' + dataset.mappings[property].sort);\n // }\n // }\n // }\n // if(sort.length > 0){\n // mergedQuery.orderByFields = sort.join(',');\n // }\n // -----------------------------------------------------------------\n // check for a sort passed directly in\n\n if (dataset.mappings.sort) {\n mergedQuery.orderByFields = dataset.mappings.sort;\n }\n\n let url = `${dataset.url}/query?${serializeQueryParams(mergedQuery)}`;\n\n if (dataset.token) {\n url = `${url}&token=${dataset.token}`;\n }\n\n return url;\n}\n\nconst requestUtils = {\n getJson,\n createFeatureServiceRequest\n};\n\nexport default requestUtils;\n","import { version } from '../package.json';\nimport utils from './utils/utils';\nimport requestUtils from './utils/request';\nimport specUtils from './utils/spec';\n// import specTemplates from './charts/specs';\nimport * as d3 from 'd3';\nimport * as vg from 'vega';\n\n// get cedar root URL for loading chart specs\nconst baseUrl = (function () {\n var cdnProtocol = 'http:';\n var cdnUrl = '//esri.github.io/cedar/js';\n var src;\n if (window && window.document) {\n src = (window.document.currentScript && window.document.currentScript.src);\n if (src) {\n // real browser, get base url from current script\n return src.substr(0, src.lastIndexOf('/'));\n } else {\n // ie, set base url to CDN\n // NOTE: could fallback to CDN only if can't find any scripts named cedar\n return (window.document.location ? window.document.location.protocol : cdnProtocol) + cdnUrl;\n }\n } else {\n // node, set base url to CDN\n return cdnProtocol + cdnUrl;\n }\n})();\n\nexport default class Cedar {\n /**\n * Creates a new Chart object.\n *\n * @example\n * var chart = new Cedar({\n * \"type\": \"bar\"\n * \"dataset\":\n * \"url\":\"http://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Education_WebMercator/MapServer/5\",\n * \"query\": {\n * \"groupByFieldsForStatistics\": \"FACUSE\",\n * \"outStatistics\": [{\n * \"statisticType\": \"sum\",\n * \"onStatisticField\": \"TOTAL_STUD\",\n * \"outStatisticFieldName\": \"TOTAL_STUD_SUM\"\n * }]\n * },\n * \"mappings\":{\n * \"sort\": \"TOTAL_STUD_SUM DESC\",\n * \"x\": {\"field\":\"FACUSE\",\"label\":\"Facility Use\"},\n * \"y\": {\"field\":\"TOTAL_STUD_SUM\",\"label\":\"Total Students\"}\n * }\n * }\n * });\n *\n * @param {Object} options\n * @param {String} options.type - Chart type as a chartType (\"bar\") or a URL to a Cedar specification\n * @param {Object} options.dataset - Dataset definition including Source and Style mappings\n * @param {String} options.dataset.url - GeoService Layer URL\n *\n * \"url\":\"http://.../rest/services/DATA/Education/MapServer/5\"\n * @param {Object} options.dataset.query - GeoServices Layer query parameters (where, bbox, outStatistics) [optional]\n *\n * \"query\": {\n * \"groupByFieldsForStatistics\": \"FACUSE\",\n * \"outStatistics\": [{\n * \"statisticType\": \"sum\",\n * \"onStatisticField\": \"TOTAL_STUD\",\n * \"outStatisticFieldName\": \"TOTAL_STUD_SUM\" }] }\n * @param {Object} options.dataset.data - Inline feature collection, alternative to data from a URL\n *\n * \"data\": {\"features\":[{\"attributes\":{\"ZIP_CODE\":20005,\"TOTAL_STUD_SUM\":327}}]}\n * @param {Object} options.dataset.mappings - Relates data items to the chart style definition\n * @param {Object} options.override - Changes to the \"options.type\" chart specification\n * @param {Object} options.tooltip - Optional on-hover tooltip. Element has class=\"cedar-tooltip\" for styling.\n * @param {String} options.tooltip.id - Optional HTML element to use for tooltip. (default: unique id created)\n * @param {String} options.tooltip.title - Templated tooltip heading. Uses \"{Variable} template format\"\n * @param {String} options.tooltip.content - Templated tooltip body text. Uses \"{Variable} template format\"\n * @return {Object} new Cedar chart object\n */\n constructor (options) {\n this.version = version;\n // Pull templates in\n // this.chartTypes = specTemplates;\n\n let opts = options || {};\n\n let spec;\n\n this.baseUrl = baseUrl;\n this.chartTypes = ['bar', 'bar-horizontal', 'bubble', 'grouped', 'pie', 'scatter', 'sparkline', 'time', 'time-trendline'];\n\n // Cedar configs such as size..\n this.width = undefined;\n this.height = undefined;\n this.autolabels = true;\n this.maxLabelLength = undefined;\n\n // Array to hold event handlers\n this._events = [];\n\n // initialize internal definition\n this._definition = specUtils.defaultDefinition();\n\n // initialize vega view aka chart\n this._view = undefined;\n\n // the vega tooltip\n this._tooltip = undefined;\n\n // transform function\n this._transform = undefined;\n\n // Queue to hold methods called while xhrs are in progress\n this._methodQueue = [];\n\n // Set a base timeout\n this._timeout = undefined;\n\n // override the base timeout\n if (opts.timeout) {\n this._timeout = opts.timeout;\n }\n\n // override the base url\n if (opts.baseUrl) {\n this.baseUrl = opts.baseUrl;\n }\n\n /**\n * Flag used to determine if the library is waiting for an xhr to return.\n * @access private\n */\n this._pendingXhr = false;\n\n /**\n * Definition\n */\n\n if (opts.definition) {\n if (typeof opts.definition === 'object') {\n // hold onto the definition\n this._definition = opts.definition;\n } else if (typeof opts.definition === 'string') {\n // assume it's a url (relative or absolute) and fetch the def object\n this._pendingXhr = true;\n requestUtils.getJson(opts.definition, (err, data) => {\n if (err) {\n throw new Error('Error fetching definition object', err);\n }\n this._pendingXhr = false;\n this._definition = data;\n this._purgeMethodQueue();\n }, this._timeout);\n } else {\n throw new Error('parameter definition must be an object or string (url)');\n }\n }\n\n // if there are overrides\n if (opts.override) {\n this._definition.override = opts.override;\n }\n\n /**\n * Specs\n */\n\n // first, check for pre-defined chart type passed in as 'type'\n spec = this._getSpecificationUrl(opts.type);\n\n // If url or object passed use that...\n if (opts.specification) {\n spec = opts.specification;\n }\n\n if (spec) {\n // is it an object or string, assumed to be url\n if (typeof spec === 'object') {\n // hold onto the template\n this._definition.specification = spec;\n } else if (typeof spec === 'string') {\n // assume it's a url (rel or abs) and fetch the template object\n this._pendingXhr = true;\n this._pendingXhr = true;\n requestUtils.getJson(spec, (err, data) => {\n if (err) {\n throw new Error('Error fetching template object', err);\n }\n this._pendingXhr = false;\n this._definition.specification = data;\n this._purgeMethodQueue();\n }, this._timeout);\n } else {\n throw new Error('parameter specification must be an object or string (url)');\n }\n }\n\n // Allow a dataset to be passed in....\n if (opts.dataset && typeof opts.dataset === 'object') {\n opts.dataset.query = utils.mixin({}, specUtils.defaultQuery(), opts.dataset.query);\n // Assign it\n this._definition.dataset = opts.dataset;\n }\n\n /**\n * Tooltip\n */\n // allow a tooltip to be passed in...\n if (opts.tooltip && typeof opts.tooltip === 'object') {\n this.tooltip = opts.tooltip;\n } else {\n // Build a default tooltip based on first two imputs....\n const inputs = [];\n for (let input in this._definition.dataset.mappings) {\n if (this._definition.dataset.mappings.hasOwnProperty(input)) {\n const field = this._definition.dataset.mappings[input].field;\n if (field !== undefined && field !== null) {\n inputs.push(field);\n }\n }\n }\n if (inputs.length >= 2) {\n this.tooltip = {\n 'title': `{${inputs[0]}}`,\n 'content': `{${inputs[1]}}`\n };\n }\n }\n\n /**\n * tranform\n */\n // Allow a transform func to pass in\n if (opts.transform && typeof opts.transform === 'function') {\n this._transform = opts.transform;\n }\n }\n\n /**\n * Properties\n */\n // Datasets\n get dataset () {\n return this._definition.dataset;\n }\n set dataset (val) {\n this._definition.dataset = val;\n }\n\n // Specification\n get specification () {\n return this._definition.specification;\n }\n set specification (val) {\n this._definition.specification = val;\n }\n\n // override\n get override () {\n return this._definition.override;\n }\n set override (val) {\n this._definition.override = val;\n // return this.update(); // TODO is this the best way?\n }\n\n // Tooltip\n get tooltip () {\n return this._definition.tooltip;\n }\n set tooltip (val) {\n this._definition.tooltip = val;\n if (this._definition.tooltip.id === undefined || this._definition.tooltip.id === null) {\n this._definition.tooltip.id = `cedar-${Date.now()}`;\n }\n }\n\n // transform\n get transform () {\n return this._transform;\n }\n set transform (val) {\n this._transform = val;\n }\n\n _getSpecificationUrl (spec) {\n if (this.chartTypes.indexOf(spec) !== -1) {\n spec = `${this.baseUrl}/charts/${this.chartTypes[this.chartTypes.indexOf(spec)]}.json`;\n }\n return spec;\n }\n\n /**\n * Inspect the current state of the Object\n * and determine if we have sufficient information\n * to render the chart\n * @return {object} Hash of the draw state + any missing requirements\n */\n canDraw () {\n // dataset?\n // dataset.url || dataset.data?\n // dataset.mappings?\n // specification?\n // specification.template?\n // specification.inputs?\n // specification.inputs ~ dataset.mappings?\n\n return {drawable: true, errs: []};\n }\n\n /**\n * Draw the chart into the DOM element\n *\n * @example\n *\n * var chart = new Cedar({\n * \"type\": \"scatter\",\n * \"dataset\":{\n * \"url\":\"http://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Education_WebMercator/MapServer/5\",\n * \"query\":{},\n * \"mappings\":{\n * \"x\": {\"field\":\"POPULATION_ENROLLED_2008\",\"label\":\"Enrolment 2008\"},\n * \"y\": {\"field\":\"SQUARE_FOOTAGE\",\"label\":\"Square Footage\"},\n * \"color\":{\"field\":\"FACUSE\",\"label\":\"Facility Type\"}\n * }\n * }\n * });\n *\n * chart.show({\n * elementId: \"#chart\"\n * });\n *\n * @param {object} options\n * @param {String} options.elementId [required] Id of the Dom element into which the chart will be rendered\n * @param {String} options.renderer \"canvas\" or \"svg\" (default: `svg`)\n * @param {Boolean} options.autolabels place axis labels outside any tick labels (default: false)\n * @param {String} options.token Token to be used if the data or spec are on a secured server\n */\n show (options, clb) {\n if (this._pendingXhr) {\n // TODO addToMethodQueue\n this._addToMethodQueue('show', [options, clb]);\n } else {\n let err;\n // ensure we got an elementId\n if (!options.elementId) {\n err = 'Cedar.show requires options.elementId';\n }\n // Check if element exists in the page\n if (d3.select(options.elementId)[0][0] === null) {\n err = `Element ${options.elementId} is not present in the DOM`;\n }\n\n // hold onto the id\n this._elementId = options.elementId;\n this._renderer = options.renderer || 'svg'; // default to svg\n this.width = options.width || this.height;\n this.height = options.height || this.height;\n if (options.autolabels !== undefined && options.autolabels !== null) {\n this.autolabels = options.autolabels;\n }\n\n if (options.maxLabelLength) {\n // check if truncate label length has been passed in\n this.maxLabelLength = options.maxLabelLength;\n }\n\n // hold onto the token\n if (options.token) {\n this._token = options.token;\n }\n\n if (err) {\n throw new Error(err);\n }\n\n var chk = this.canDraw();\n\n if (chk.drawable) {\n this.update(clb);\n } else {\n // report the issues\n const errs = chk.issues.join(',');\n throw new Error(`Chart can not be drawn because: ${errs}`);\n }\n }\n }\n\n /**\n * Draw the chart based on any changes to data or specifications\n * Should be called after a user modifies\n * the dataset, query, mappings, chart specification or element size\n *\n * @example\n * dataset = {\"url\": \"...\", \"mappings\": {\"x\": {\"field\": \"STATE\"}, \"y\": {\"field\": \"POPULATION\"}}};\n * chart = new Cedar({ \"type\": \"bar\", \"dataset\": dataset });\n * chart.show({elementId: \"#chart\"});\n * chart.dataset.query.where = \"POPULATION>30000\";\n * chart.update();\n */\n update (clb) {\n if (this._view) {\n this.emit('update-start');\n }\n\n if (this._pendingXhr) {\n this._addToMethodQueue('update');\n } else {\n if (this._view) {\n // remove handlers\n // TODO Remove existing handlers\n this._remove(this._view);\n }\n\n try {\n // Creates the HTML Div and styling if not already created\n if (this._definition.tooltip) {\n this._createTooltip(this._definition.tooltip.id);\n }\n\n // Ensure we have required inputs or defaults\n let compiledMappings = specUtils.applyDefaultsToMappings(this._definition.dataset.mappings, this._definition.specification.inputs);\n\n let queryFromSpec = utils.mixin({}, this._definition.specification.query, this._definition.dataset.query);\n queryFromSpec = JSON.parse(utils.supplant(JSON.stringify(queryFromSpec), compiledMappings));\n\n // allow binding to query properties\n compiledMappings.query = queryFromSpec;\n\n // compile the template + mappings --> vega spec\n let spec = JSON.parse(utils.supplant(JSON.stringify(this._definition.specification.template), compiledMappings));\n\n // merge in user specified style overrides\n spec = utils.mergeRecursive(spec, this._definition.override);\n\n // if the spec has a url in the data node, delete it TODO: need to readress this.\n if (spec.data[0].url) {\n delete spec.data[0].url;\n }\n\n if (this._definition.dataset.data) {\n // create the data node using the passed in data\n spec.data[0].values = this._definition.dataset.data; // TODO: only works on first spec, need to address for multiple datasets.\n\n // Send to vega\n this._renderSpec(spec, clb);\n } else {\n // We need to fetch the data so....\n const url = requestUtils.createFeatureServiceRequest(this._definition.dataset, queryFromSpec);\n\n // create a callback closure to carry the spec\n const cb = (err, data) => {\n // Normalize error response\n if (!err && !!data.error) {\n err = new Error(data.error.message || data.error.details[0]);\n }\n // if no errors then continue...\n if (!err) {\n if (this._transform && typeof this._transform === 'function') {\n data = this._transform(data, this._definition.dataset);\n }\n // TODO add error handlers for xhr and AGS errors.\n spec.data[0].values = data;\n // send to vega\n this._renderSpec(spec, clb);\n } else {\n // optional callback\n if (!!clb && typeof clb === 'function') {\n clb(err, data);\n }\n }\n };\n\n // fetch the data from the service\n requestUtils.getJson(url, cb, this._timeout);\n }\n } catch (ex) {\n throw (ex);\n }\n }\n }\n\n /**\n * RENDER CHART FUNCTIONS\n *\n *\n * Render a compiled Vega specification using vega runtime\n */\n\n _renderSpec (spec, clb) {\n if (this.autolabels === true) {\n spec = this._placeLabels(spec);\n spec = this._placeaAxisTicks(spec);\n }\n // Use vega to parse the spec\n // It will handle the spec as an object or url\n vg.parse.spec(spec, (err, chartCtor) => {\n // create the view\n this._view = chartCtor({\n el: this._elementId,\n renderer: this._renderer\n });\n\n const width = this.width || parseInt(d3.select(this._elementId).style('width'), 10) || 500;\n const height = this.height || parseInt(d3.select(this._elementId).style('height'), 10) || 500;\n\n // render into the element\n this._view.width(width).height(height).update();\n\n // attach event proxies\n this._attach(this._view);\n\n if (this._view) {\n this.emit('update-end');\n }\n\n // expose errors\n if (!!clb && typeof clb === 'function') {\n clb(err, spec);\n }\n });\n }\n\n /**\n * AXIS TICK FUNCTIONS START HERE\n *\n *\n * Automatically determines axis title placement\n *\n * Calculates the maximum length of a tick label and adds padding\n */\n\n _placeLabels (spec) {\n try {\n const fields = {};\n const lengths = {};\n const inputs = [];\n // Get all inputs that may be axes\n for (let input in this._definition.dataset.mappings) {\n // check also if property is not inherited from prototype\n if (this._definition.dataset.mappings.hasOwnProperty(input)) {\n const field = this._definition.dataset.mappings[input].field;\n if (field) {\n inputs.push(input);\n fields[input] = field;\n lengths[input] = 0;\n }\n }\n }\n let length = 0;\n\n // find the max length value for each axis\n spec.data[0].values.features.forEach((feature) => {\n inputs.forEach((axis) => {\n length = (feature.attributes[fields[axis]] || '').toString().length;\n if (this.maxLabelLength) {\n // Need to make sure that the gap between title and labels isn't ridiculous\n length = length < (this.maxLabelLength + 1) ? length : this.maxLabelLength;\n }\n if (length > lengths[axis]) {\n lengths[axis] = length;\n }\n });\n });\n\n // Change each axis title offset based on longest value\n inputs.forEach((axis, index) => {\n let angle = 0;\n if (!!spec.axes && !!spec.axes[index]) {\n if (spec.axes[index].properties.labels.angle) {\n angle = spec.axes[index].properties.labels.angle.value;\n }\n if (spec.axes[index].type === 'y') {\n angle = 100 - angle;\n }\n if (this.maxLabelLength) {\n // Set max length of axes titles\n spec.axes[index].properties.labels.text = {'template': `{{ datum.data | truncate:\"${this.maxLabelLength}\"}}`};\n }\n // set title offset\n spec.axes[index].titleOffset = Math.abs(lengths[axis] * angle / 100 * 8) + 35;\n }\n });\n return spec;\n } catch (ex) {\n throw (ex);\n }\n }\n\n /**\n * Automatically determines number of axis tick marks\n *\n * Calculates the maximum length of a tick label and adds padding\n * TODO: remove expectation that there are both x,y axes\n */\n\n _placeaAxisTicks (spec) {\n if (spec.axes) {\n try {\n const width = this.width || parseInt(d3.select(this._elementId).style('width'), 10) || 500;\n const height = this.height || parseInt(d3.select(this._elementId).style('height'), 10) || 500;\n\n spec.axes[0].ticks = width / 100;\n if (spec.axes[1]) {\n spec.axes[1].ticks = height / 30;\n }\n } catch (ex) {\n throw (ex);\n }\n }\n return spec;\n }\n\n /**\n * TOOLTIP LOGIC HERE\n *\n * Instantiates the tooltip element and styling\n * @access private\n */\n _createTooltip (elem) {\n let tooltipDiv = document.getElementById(elem);\n\n // Check if tooltip has been created or not...\n if (tooltipDiv) {\n return tooltipDiv;\n }\n\n // TODO: remove inline CSS\n let style = document.createElement('style');\n style.type = 'text/css';\n style.innerHTML = '.cedar-tooltip {background-color: white; padding: 3px 10px; color: #333; margin: -30px 0 0 20px; position: absolute; z-index: 2000; font-size: 10px; border: 1px solid #BBB;} .cedar-tooltip .title {font-size: 13pt; font-weight: bold; } .cedar-tooltip .content {font-size: 10pt; } ';\n document.getElementsByTagName('head')[0].appendChild(style);\n\n tooltipDiv = document.createElement('div');\n tooltipDiv.className = 'cedar-tooltip';\n tooltipDiv.id = elem;\n tooltipDiv.cssText = 'display: none';\n // We need tooltip at the top of the page\n document.body.insertBefore(tooltipDiv, document.body.firstChild);\n\n this.on('mouseout', (event, data) => {\n this._updateTooltip(event, null);\n });\n this.on('mousemove', (event, data) => {\n this._updateTooltip(event, data);\n });\n return tooltipDiv;\n }\n\n /**\n * Places the tooltipe and fills in content\n *\n * @access private\n */\n _updateTooltip (event, data) {\n let cedartip = document.getElementById(this._definition.tooltip.id);\n if (!data) {\n cedartip.style.display = 'none';\n return;\n }\n cedartip.style.top = `${event.pageY}px`;\n cedartip.style.left = `${event.pageX}px`;\n cedartip.style.display = 'block';\n\n let content = `${this._definition.tooltip.title}${this._definition.tooltip.content}
`;\n\n cedartip.innerHTML = content.replace(/\\{(\\w+)\\}/g, (match, $1) => {\n return data[$1];\n });\n }\n\n /**\n * EVENT LOGIC HERE\n *\n *\n * Add a handler for the named event.\n * Events:\n * - mouseover\n * - mouseout\n * - click\n * - update-start\n * - update-end\n *\n *\n *\n * Callback from Cedar events\n * - callback Cedar~eventCallback\n * - param {Object} event - event response such as mouse location\n * - param {Object} data - chart data object\n *\n * @example\n * var chart = new Cedar({ ... });\n * chart.on('mouseover', function(event, data) {\n * console.log(\"Mouse Location:\", [event.offsetX, event.offsetY]);\n * console.log(\"Data value:\", data[Object.keys(data)[0]]);\n * });\n *\n * @param {String} eventName name of the event that invokes callback\n * @param {Cedar~eventCallback} callback - The callback that handles the event.\n */\n on (evtName, callback) {\n this._events.push({type: evtName, callback});\n }\n /**\n * Remove a hanlder for the named event\n */\n off (evtName, callback) {\n this._events.forEach((registeredEvent, index, object) => {\n if (registeredEvent.type === evtName && registeredEvent.callback === callback) {\n object.splice(index, 1);\n }\n });\n }\n\n /**\n * Trigger a callback\n * @param {string} eventName - [\"mouseover\",\"mouseout\",\"click\",\"update-start\",\"update-end\"]\n */\n emit (eventName) {\n if (!!this._view._handler._handlers[ eventName ] && !!this._view._handler._handlers[ eventName ][0]) {\n this._view._handler._handlers[ eventName ][0].handler();\n }\n }\n\n /**\n * Attach the generic proxy hanlders to the chart view\n * @access private\n */\n _attach (view) {\n view.on('mouseover', this._handler('mouseover'));\n view.on('mouseout', this._handler('mouseout'));\n view.on('mousemove', this._handler('mousemove'));\n view.on('click', this._handler('click'));\n view.on('update-start', this._handler('update-start'));\n view.on('update-end', this._handler('update-end'));\n }\n\n /**\n * Remove all event handlers from the view\n * @access private\n */\n _remove (view) {\n view.off('mouseover');\n view.off('mouseout');\n view.off('mousemove');\n view.off('click');\n view.off('update-start');\n view.off('update-end');\n }\n\n /**\n * Creates an entry in the method queue, executed\n * once a pending xhr is completed\n * @access private\n */\n _addToMethodQueue (name, args) {\n this._methodQueue.push({ method: name, args: args });\n }\n\n /**\n * empties the method queue by calling the queued methods\n * This helps build a more syncronous api, while still\n * doing async things in the code\n * @access private\n */\n _purgeMethodQueue () {\n if (this._methodQueue.length > 0) {\n this._methodQueue.forEach((action, index) => {\n this[action.method].apply(this, action.args);\n });\n }\n }\n\n /**\n * Generic event handler proxy\n * @access private\n */\n _handler (evtName) {\n // return a handler function w/ the events hash closed over\n const handler = (evt, item) => {\n this._events.forEach((registeredHandler) => {\n if (registeredHandler.type === evtName) {\n // invoke the callback with the data\n if (item) {\n registeredHandler.callback(evt, item.datum.attributes);\n } else {\n registeredHandler.callback(evt, null);\n }\n }\n });\n };\n return handler;\n }\n\n /**\n * SELECT LOGIC STARTS HERE\n *\n * Highlight marker based on attribute value\n *\n * @example\n * chart = new Cedar({...});\n * chart.select({key: 'ZIP_CODE', value: '20002'});\n *\n * @param {object} options - Object(key, value) to match. Calls hover on work\n * @returns {Array} items - array of chart objects that match the criteria\n */\n\n select (options) {\n let view = this._view;\n let items = view.model().scene().items[0].items[0].items;\n\n items.forEach((item) => {\n if (item.datum.attributes[options.key] === options.value) {\n if (item.hasPropertySet('hover')) {\n this._view.update({props: 'hover', items: item});\n }\n }\n });\n\n return items;\n }\n\n /**\n * Removes highlighted chart items\n *\n * If \"options\" are used, only clear specific items, otherwise clears all highlights.\n * @param {Object} options - Object(key, value) to match. Calls hover on mark\n * @returns {Array} items - array of chart objects that match the criteria, or null if all items.\n */\n\n clearSelection (options) {\n let view = this._view;\n\n if (!!options && !!options.key) {\n let items = view.model().scene().items[0].items[0].items;\n items.forEach((item) => {\n if (item.datum.attributes[options.key] === options.value) {\n this._view.update({props: 'update', items: item});\n }\n });\n return items;\n } else {\n // clear all\n this._view.update();\n return null;\n }\n }\n\n static getJson (url, callback, timeout) {\n return requestUtils.getJson(url, callback, timeout);\n }\n\n /**\n * Other now exposed utils!\n */\n static _validateMappings (inputs, mappings) {\n return utils.validateMappings(inputs, mappings);\n }\n static _validateData (data, mappings) {\n return utils.validateData(data, mappings);\n }\n static _createFeatureServiceRequest (dataset, queryFromSpec) {\n return requestUtils.createFeatureServiceRequest(dataset, queryFromSpec);\n }\n static _getMappingFieldName (mappingName, fieldName) {\n return utils.getMappingFieldName(mappingName, fieldName);\n }\n}\n"],"names":["const","let","d3.entries","getJson","d3.xhr","xhr","this","d3.select","vg.parse","name"],"mappings":"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"} \ No newline at end of file diff --git a/dist/cedar.min.js b/dist/cedar.min.js new file mode 100644 index 00000000..32aae2ae --- /dev/null +++ b/dist/cedar.min.js @@ -0,0 +1,7 @@ +/** +* arcgis-cedar - v0.8.2 - Wed Jan 11 2017 11:48:57 GMT-0500 (EST) +* Copyright (c) 2017 Environmental Systems Research Institute, Inc. +* Apache-2.0 +*/ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("d3"),require("vega")):"function"==typeof define&&define.amd?define(["d3","vega"],e):t.Cedar=e(t.d3,t.vg)}(this,function(t,e){"use strict";function i(e){for(var i=arguments.length,n=Array(i);i--;)n[i]=arguments[i];for(var o=[].concat(n),r=1;r"+this._definition.tooltip.content+"
",i.innerHTML=n.replace(/\{(\w+)\}/g,function(t,i){return e[i]})},w.prototype.on=function(t,e){this._events.push({type:t,callback:e})},w.prototype.off=function(t,e){this._events.forEach(function(i,n,o){i.type===t&&i.callback===e&&o.splice(n,1)})},w.prototype.emit=function(t){this._view._handler._handlers[t]&&this._view._handler._handlers[t][0]&&this._view._handler._handlers[t][0].handler()},w.prototype._attach=function(t){t.on("mouseover",this._handler("mouseover")),t.on("mouseout",this._handler("mouseout")),t.on("mousemove",this._handler("mousemove")),t.on("click",this._handler("click")),t.on("update-start",this._handler("update-start")),t.on("update-end",this._handler("update-end"))},w.prototype._remove=function(t){t.off("mouseover"),t.off("mouseout"),t.off("mousemove"),t.off("click"),t.off("update-start"),t.off("update-end")},w.prototype._addToMethodQueue=function(t,e){this._methodQueue.push({method:t,args:e})},w.prototype._purgeMethodQueue=function(){var t=this;this._methodQueue.length>0&&this._methodQueue.forEach(function(e,i){t[e.method].apply(t,e.args)})},w.prototype._handler=function(t){var e=this,i=function(i,n){e._events.forEach(function(e){e.type===t&&(n?e.callback(i,n.datum.attributes):e.callback(i,null))})};return i},w.prototype.select=function(t){var e=this,i=this._view,n=i.model().scene().items[0].items[0].items;return n.forEach(function(i){i.datum.attributes[t.key]===t.value&&i.hasPropertySet("hover")&&e._view.update({props:"hover",items:i})}),n},w.prototype.clearSelection=function(t){var e=this,i=this._view;if(t&&t.key){var n=i.model().scene().items[0].items[0].items;return n.forEach(function(i){i.datum.attributes[t.key]===t.value&&e._view.update({props:"update",items:i})}),n}return this._view.update(),null},w.getJson=function(t,e,i){return v.getJson(t,e,i)},w._validateMappings=function(t,e){return _.validateMappings(t,e)},w._validateData=function(t,e){return _.validateData(t,e)},w._createFeatureServiceRequest=function(t,e){return v.createFeatureServiceRequest(t,e)},w._getMappingFieldName=function(t,e){return _.getMappingFieldName(t,e)},Object.defineProperties(w.prototype,b),w}); +//# sourceMappingURL=cedar.min.js.map diff --git a/dist/cedar.min.js.map b/dist/cedar.min.js.map new file mode 100644 index 00000000..76242e6c --- /dev/null +++ b/dist/cedar.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":null,"sources":["../src/utils/utils.js","../src/utils/spec.js","../src/utils/request.js","../src/cedar.js"],"sourcesContent":["import * as d3 from 'd3';\n/**\n * Merges n objects\n * @param {object} source Empty object that other objects will be merged into\n * @return {Object} Merged objects\n */\nexport function mixin (source) {\n const args = [...arguments];\n for (let i = 1; i < args.length; i++) {\n d3.entries(args[i]).forEach((p) => {\n source[p.key] = p.value;\n });\n }\n return source;\n}\n\n/**\n * Recursively merge properties of two objects\n */\nexport function mergeRecursive (obj1, obj2) {\n for (let p in obj2) {\n if (obj2.hasOwnProperty(p)) {\n try {\n // Property in destination object set; update its value.\n if (obj2[p].constructor === Object || obj2[p].constructor === Array) {\n obj1[p] = mergeRecursive(obj1[p], obj2[p]);\n } else {\n obj1[p] = obj2[p];\n }\n } catch (e) {\n // Property in destination object not set; create it and set its value\n obj1[p] = obj2[p];\n }\n }\n }\n return obj1;\n}\n\n/**\n * Token replacement on a string\n * @param {string} template string template\n * @param {object} params Object hash that maps to the tokens to be replaced\n * @return {string} string with values replaced\n */\nexport function supplant (template, params) {\n const t = template.replace(/{([^{}]*)}/g,\n (a, b) => {\n const r = getTokenValue(params, b);\n\n return typeof r === 'string' || typeof r === 'number' ? r : a;\n }\n );\n return t.replace(/\"{([^{}]*)}\"/g,\n (a, b) => {\n let r = getTokenValue(params, b);\n return (!!r && r.constructor === Array) ? JSON.stringify(r) : a;\n });\n}\n\n/**\n * Get the value of a token from a hash\n * @param {object} tokens Hash {a: 'a', b: { c: 'c'} }\n * @param {string} tokenName Property name: 'a' would yield 'a', 'b.c' would yield 'c'\n * @return {Any} Returns value contained within property\n * Pulled from gulp-token-replace (MIT license)\n * https://github.com/Pictela/gulp-token-replace/blob/master/index.js\n */\nexport function getTokenValue (tokens, tokenName) {\n let tmpTokens = tokens;\n let tokenNameParts = tokenName.split('.');\n for (let i = 0; i < tokenNameParts.length; i++) {\n if (tmpTokens.hasOwnProperty(tokenNameParts[i])) {\n tmpTokens = tmpTokens[tokenNameParts[i]];\n } else {\n return null;\n }\n }\n return tmpTokens;\n}\n\n /**\n * Helper function that validates that the\n * mappings hash contains values for all\n * the inputs\n * @param {array} inputs Array of inputs\n * @param {object} mappings Hash of mappings\n * @return {array} Missing mappings\n * @access private\n */\nexport function validateMappings (inputs, mappings) {\n return inputs.filter((input) => {\n if (input.required && !mappings[input.name]) {\n return input;\n }\n });\n}\n\n /**\n * Validate that the incoming data has the fields expected\n * in the mappings\n * @access private\n */\nexport function validateData (data, mappings) {\n const missingInputs = [];\n if (!data.features || !Array.isArray(data.features)) {\n throw new Error('Data is expected to have features array!');\n }\n const firstRow = data.features[0].attributes;\n for (let key in mappings) {\n if (mappings.hasOwnProperty(key)) {\n let fld = getMappingFieldName(key, mappings[key].field);\n if (!firstRow.hasOwnProperty(fld)) {\n missingInputs.push(fld);\n }\n }\n }\n return missingInputs;\n}\n\n /**\n * TODO does nothing, must figure out.\n * Centralize and abstract the computation of\n * expected field names, based on the mapping name\n * @access private\n */\nexport function getMappingFieldName (mappingName, fieldName) {\n // this function why?\n\n let name = fieldName;\n // if(mappingName.toLowerCase() === 'count'){\n // name = fieldName + '_SUM';\n // }\n return name;\n}\n\nconst utils = {\n mixin,\n supplant,\n mergeRecursive,\n getTokenValue,\n validateMappings,\n validateData,\n getMappingFieldName\n};\n\nexport default utils;\n","/**\n * Return a default definition Object\n * @return {Object} Default definition\n */\nexport function defaultDefinition () {\n return {\n dataset: {\n query: defaultQuery()\n },\n template: {}\n };\n}\n\n/**\n * Return AGO query defaults\n * @return {Object} Default query\n */\nexport function defaultQuery () {\n return {\n where: '1=1',\n returnGeometry: false,\n returnDistinctValues: false,\n returnIdsOnly: false,\n returnCountOnly: false,\n outFields: '*',\n sqlFormat: 'standard',\n f: 'json'\n };\n}\n\n/**\n * Ensure that all required inputs exist in mappings\n * @param {object} mappings Mappings object\n * @param {array} inputs Array of inputs in specification\n * @return {object} Returns mappings\n */\nexport function applyDefaultsToMappings (mappings, inputs) {\n const errs = [];\n // iterate over inputs\n for (let i = 0; i < inputs.length; i++) {\n const input = inputs[i];\n\n // If required but not there\n if (input.required && !mappings[input.name]) {\n errs.push(input.name);\n }\n\n // if it's not required, has a default and not in the mappings\n if (!input.required && !mappings[input.name] && input['default']) {\n // add the default\n mappings[input.name] = input['default'];\n }\n }\n if (errs.length > 0) {\n throw new Error(`Required Mappings Missing: ${errs.join(',')}`);\n } else {\n return mappings;\n }\n}\n\nconst specUtils = {\n defaultDefinition,\n defaultQuery,\n applyDefaultsToMappings\n};\n\nexport default specUtils;\n","import * as d3 from 'd3';\nimport { mixin } from './utils';\nimport { defaultQuery } from './spec';\n\n/**\n * Takes in params, iterates over them, encodes and returns stringified and encoded query\n *\n * @param {object} params - merged default and user defined parameters\n *\n * @returns {string} - stringified and encoded query\n */\nfunction serializeQueryParams (params) {\n const str = [];\n for (const param in params) {\n if (params.hasOwnProperty(param)) {\n let val = params[param];\n if (typeof val !== 'string') {\n val = JSON.stringify(val);\n }\n str.push(`${encodeURIComponent(param)}=${encodeURIComponent(val)}`);\n }\n }\n const queryString = str.join('&');\n return queryString;\n}\n\n/**\n * Helper function to request JSON from a url\n * @param {string} url URL to request from\n * @param {Function} callback Callback function\n * @param {number} timeout Timeout on request\n * @return {object} Response object\n */\nexport function getJson (url, callback, timeout) {\n const cb = (err, data) => {\n // if timeout error then return a timeout error\n if (err && err.response === '') {\n callback(new Error('This service is taking too long to respond, unable to chart'));\n } else if (err) {\n // Other errors return generic error.\n callback(new Error(`Error loading ${url} with a response of: ${err.message}`));\n } else {\n callback(null, JSON.parse(data.responseText));\n }\n };\n if (url.length > 2000) {\n const uri = url.split('?');\n d3.xhr(uri[0])\n .on('beforesend', (xhr) => { xhr.timeout = timeout; xhr.ontimeout = xhr.onload; })\n .header('Content-Type', 'application/x-www-form-urlencoded')\n .post(uri[1], cb);\n } else {\n d3.xhr(url)\n .on('beforesend', (xhr) => { xhr.timeout = timeout; xhr.ontimeout = xhr.onload; })\n .get(cb);\n }\n}\n\n/**\n * Given a dataset hash create a feature service request\n * @param {object} dataset Dataset object\n * @param {object} queryFromSpec Query passed in by the user\n * @return {string} url string\n */\nexport function createFeatureServiceRequest (dataset, queryFromSpec) {\n const mergedQuery = mixin({}, defaultQuery(), queryFromSpec);\n\n // Handle bbox\n if (mergedQuery.bbox) {\n // make sure a geometry was not also passed in\n if (mergedQuery.geometry) {\n throw new Error('Dataset.query can not have both a geometry and a bbox specified');\n }\n // Get the bbox (w,s,e,n)\n const bboxArr = mergedQuery.bbox.split(',');\n\n // Remove it so it's not serialized as-is\n delete mergedQuery.bbox;\n\n // cook it into a json string\n mergedQuery.geometry = JSON.stringify({\n xmin: bboxArr[0],\n ymin: bboxArr[2],\n xmax: bboxArr[1],\n ymax: bboxArr[3]\n });\n // set spatial ref as geographic\n mergedQuery.inSR = '4326';\n }\n\n if (!mergedQuery.groupByFieldsForStatistics && !!dataset.mappings.group) {\n mergedQuery.groupByFieldsForStatistics = dataset.mappings.group.field;\n }\n if (!mergedQuery.outStatistics && !!dataset.mappings.count) {\n // TODO Why are we explicitlystating _SUM as a stats type?\n mergedQuery.orderByFields = `${dataset.mappings.count.field}_SUM`;\n mergedQuery.outStatistics = JSON.stringify([{\n statisticType: 'sum',\n onStatisticField: dataset.mappings.count.field,\n outStatisticFieldName: `${dataset.mappings.count.field}_SUM`\n }]);\n }\n\n // iterate the mappings keys to check for sort\n // -----------------------------------------------------------------\n // This approach would seem 'clean' but if there are multiple fields\n // to sort by, the order would be determined by how javascript decides to\n // iterate the mappings property hash.\n // Thus, using mappings.sort gives the developer explicit control\n // -----------------------------------------------------------------\n // var sort = [];\n // for (var property in dataset.mappings) {\n // if (dataset.mappings.hasOwnProperty(property)) {\n // if(dataset.mappings[property].sort){\n // //ok - build up the sort\n // sort.push(dataset.mappings[property].field + ' ' + dataset.mappings[property].sort);\n // }\n // }\n // }\n // if(sort.length > 0){\n // mergedQuery.orderByFields = sort.join(',');\n // }\n // -----------------------------------------------------------------\n // check for a sort passed directly in\n\n if (dataset.mappings.sort) {\n mergedQuery.orderByFields = dataset.mappings.sort;\n }\n\n let url = `${dataset.url}/query?${serializeQueryParams(mergedQuery)}`;\n\n if (dataset.token) {\n url = `${url}&token=${dataset.token}`;\n }\n\n return url;\n}\n\nconst requestUtils = {\n getJson,\n createFeatureServiceRequest\n};\n\nexport default requestUtils;\n","import { version } from '../package.json';\nimport utils from './utils/utils';\nimport requestUtils from './utils/request';\nimport specUtils from './utils/spec';\n// import specTemplates from './charts/specs';\nimport * as d3 from 'd3';\nimport * as vg from 'vega';\n\n// get cedar root URL for loading chart specs\nconst baseUrl = (function () {\n var cdnProtocol = 'http:';\n var cdnUrl = '//esri.github.io/cedar/js';\n var src;\n if (window && window.document) {\n src = (window.document.currentScript && window.document.currentScript.src);\n if (src) {\n // real browser, get base url from current script\n return src.substr(0, src.lastIndexOf('/'));\n } else {\n // ie, set base url to CDN\n // NOTE: could fallback to CDN only if can't find any scripts named cedar\n return (window.document.location ? window.document.location.protocol : cdnProtocol) + cdnUrl;\n }\n } else {\n // node, set base url to CDN\n return cdnProtocol + cdnUrl;\n }\n})();\n\nexport default class Cedar {\n /**\n * Creates a new Chart object.\n *\n * @example\n * var chart = new Cedar({\n * \"type\": \"bar\"\n * \"dataset\":\n * \"url\":\"http://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Education_WebMercator/MapServer/5\",\n * \"query\": {\n * \"groupByFieldsForStatistics\": \"FACUSE\",\n * \"outStatistics\": [{\n * \"statisticType\": \"sum\",\n * \"onStatisticField\": \"TOTAL_STUD\",\n * \"outStatisticFieldName\": \"TOTAL_STUD_SUM\"\n * }]\n * },\n * \"mappings\":{\n * \"sort\": \"TOTAL_STUD_SUM DESC\",\n * \"x\": {\"field\":\"FACUSE\",\"label\":\"Facility Use\"},\n * \"y\": {\"field\":\"TOTAL_STUD_SUM\",\"label\":\"Total Students\"}\n * }\n * }\n * });\n *\n * @param {Object} options\n * @param {String} options.type - Chart type as a chartType (\"bar\") or a URL to a Cedar specification\n * @param {Object} options.dataset - Dataset definition including Source and Style mappings\n * @param {String} options.dataset.url - GeoService Layer URL\n *\n * \"url\":\"http://.../rest/services/DATA/Education/MapServer/5\"\n * @param {Object} options.dataset.query - GeoServices Layer query parameters (where, bbox, outStatistics) [optional]\n *\n * \"query\": {\n * \"groupByFieldsForStatistics\": \"FACUSE\",\n * \"outStatistics\": [{\n * \"statisticType\": \"sum\",\n * \"onStatisticField\": \"TOTAL_STUD\",\n * \"outStatisticFieldName\": \"TOTAL_STUD_SUM\" }] }\n * @param {Object} options.dataset.data - Inline feature collection, alternative to data from a URL\n *\n * \"data\": {\"features\":[{\"attributes\":{\"ZIP_CODE\":20005,\"TOTAL_STUD_SUM\":327}}]}\n * @param {Object} options.dataset.mappings - Relates data items to the chart style definition\n * @param {Object} options.override - Changes to the \"options.type\" chart specification\n * @param {Object} options.tooltip - Optional on-hover tooltip. Element has class=\"cedar-tooltip\" for styling.\n * @param {String} options.tooltip.id - Optional HTML element to use for tooltip. (default: unique id created)\n * @param {String} options.tooltip.title - Templated tooltip heading. Uses \"{Variable} template format\"\n * @param {String} options.tooltip.content - Templated tooltip body text. Uses \"{Variable} template format\"\n * @return {Object} new Cedar chart object\n */\n constructor (options) {\n this.version = version;\n // Pull templates in\n // this.chartTypes = specTemplates;\n\n let opts = options || {};\n\n let spec;\n\n this.baseUrl = baseUrl;\n this.chartTypes = ['bar', 'bar-horizontal', 'bubble', 'grouped', 'pie', 'scatter', 'sparkline', 'time', 'time-trendline'];\n\n // Cedar configs such as size..\n this.width = undefined;\n this.height = undefined;\n this.autolabels = true;\n this.maxLabelLength = undefined;\n\n // Array to hold event handlers\n this._events = [];\n\n // initialize internal definition\n this._definition = specUtils.defaultDefinition();\n\n // initialize vega view aka chart\n this._view = undefined;\n\n // the vega tooltip\n this._tooltip = undefined;\n\n // transform function\n this._transform = undefined;\n\n // Queue to hold methods called while xhrs are in progress\n this._methodQueue = [];\n\n // Set a base timeout\n this._timeout = undefined;\n\n // override the base timeout\n if (opts.timeout) {\n this._timeout = opts.timeout;\n }\n\n // override the base url\n if (opts.baseUrl) {\n this.baseUrl = opts.baseUrl;\n }\n\n /**\n * Flag used to determine if the library is waiting for an xhr to return.\n * @access private\n */\n this._pendingXhr = false;\n\n /**\n * Definition\n */\n\n if (opts.definition) {\n if (typeof opts.definition === 'object') {\n // hold onto the definition\n this._definition = opts.definition;\n } else if (typeof opts.definition === 'string') {\n // assume it's a url (relative or absolute) and fetch the def object\n this._pendingXhr = true;\n requestUtils.getJson(opts.definition, (err, data) => {\n if (err) {\n throw new Error('Error fetching definition object', err);\n }\n this._pendingXhr = false;\n this._definition = data;\n this._purgeMethodQueue();\n }, this._timeout);\n } else {\n throw new Error('parameter definition must be an object or string (url)');\n }\n }\n\n // if there are overrides\n if (opts.override) {\n this._definition.override = opts.override;\n }\n\n /**\n * Specs\n */\n\n // first, check for pre-defined chart type passed in as 'type'\n spec = this._getSpecificationUrl(opts.type);\n\n // If url or object passed use that...\n if (opts.specification) {\n spec = opts.specification;\n }\n\n if (spec) {\n // is it an object or string, assumed to be url\n if (typeof spec === 'object') {\n // hold onto the template\n this._definition.specification = spec;\n } else if (typeof spec === 'string') {\n // assume it's a url (rel or abs) and fetch the template object\n this._pendingXhr = true;\n this._pendingXhr = true;\n requestUtils.getJson(spec, (err, data) => {\n if (err) {\n throw new Error('Error fetching template object', err);\n }\n this._pendingXhr = false;\n this._definition.specification = data;\n this._purgeMethodQueue();\n }, this._timeout);\n } else {\n throw new Error('parameter specification must be an object or string (url)');\n }\n }\n\n // Allow a dataset to be passed in....\n if (opts.dataset && typeof opts.dataset === 'object') {\n opts.dataset.query = utils.mixin({}, specUtils.defaultQuery(), opts.dataset.query);\n // Assign it\n this._definition.dataset = opts.dataset;\n }\n\n /**\n * Tooltip\n */\n // allow a tooltip to be passed in...\n if (opts.tooltip && typeof opts.tooltip === 'object') {\n this.tooltip = opts.tooltip;\n } else {\n // Build a default tooltip based on first two imputs....\n const inputs = [];\n for (let input in this._definition.dataset.mappings) {\n if (this._definition.dataset.mappings.hasOwnProperty(input)) {\n const field = this._definition.dataset.mappings[input].field;\n if (field !== undefined && field !== null) {\n inputs.push(field);\n }\n }\n }\n if (inputs.length >= 2) {\n this.tooltip = {\n 'title': `{${inputs[0]}}`,\n 'content': `{${inputs[1]}}`\n };\n }\n }\n\n /**\n * tranform\n */\n // Allow a transform func to pass in\n if (opts.transform && typeof opts.transform === 'function') {\n this._transform = opts.transform;\n }\n }\n\n /**\n * Properties\n */\n // Datasets\n get dataset () {\n return this._definition.dataset;\n }\n set dataset (val) {\n this._definition.dataset = val;\n }\n\n // Specification\n get specification () {\n return this._definition.specification;\n }\n set specification (val) {\n this._definition.specification = val;\n }\n\n // override\n get override () {\n return this._definition.override;\n }\n set override (val) {\n this._definition.override = val;\n // return this.update(); // TODO is this the best way?\n }\n\n // Tooltip\n get tooltip () {\n return this._definition.tooltip;\n }\n set tooltip (val) {\n this._definition.tooltip = val;\n if (this._definition.tooltip.id === undefined || this._definition.tooltip.id === null) {\n this._definition.tooltip.id = `cedar-${Date.now()}`;\n }\n }\n\n // transform\n get transform () {\n return this._transform;\n }\n set transform (val) {\n this._transform = val;\n }\n\n _getSpecificationUrl (spec) {\n if (this.chartTypes.indexOf(spec) !== -1) {\n spec = `${this.baseUrl}/charts/${this.chartTypes[this.chartTypes.indexOf(spec)]}.json`;\n }\n return spec;\n }\n\n /**\n * Inspect the current state of the Object\n * and determine if we have sufficient information\n * to render the chart\n * @return {object} Hash of the draw state + any missing requirements\n */\n canDraw () {\n // dataset?\n // dataset.url || dataset.data?\n // dataset.mappings?\n // specification?\n // specification.template?\n // specification.inputs?\n // specification.inputs ~ dataset.mappings?\n\n return {drawable: true, errs: []};\n }\n\n /**\n * Draw the chart into the DOM element\n *\n * @example\n *\n * var chart = new Cedar({\n * \"type\": \"scatter\",\n * \"dataset\":{\n * \"url\":\"http://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Education_WebMercator/MapServer/5\",\n * \"query\":{},\n * \"mappings\":{\n * \"x\": {\"field\":\"POPULATION_ENROLLED_2008\",\"label\":\"Enrolment 2008\"},\n * \"y\": {\"field\":\"SQUARE_FOOTAGE\",\"label\":\"Square Footage\"},\n * \"color\":{\"field\":\"FACUSE\",\"label\":\"Facility Type\"}\n * }\n * }\n * });\n *\n * chart.show({\n * elementId: \"#chart\"\n * });\n *\n * @param {object} options\n * @param {String} options.elementId [required] Id of the Dom element into which the chart will be rendered\n * @param {String} options.renderer \"canvas\" or \"svg\" (default: `svg`)\n * @param {Boolean} options.autolabels place axis labels outside any tick labels (default: false)\n * @param {String} options.token Token to be used if the data or spec are on a secured server\n */\n show (options, clb) {\n if (this._pendingXhr) {\n // TODO addToMethodQueue\n this._addToMethodQueue('show', [options, clb]);\n } else {\n let err;\n // ensure we got an elementId\n if (!options.elementId) {\n err = 'Cedar.show requires options.elementId';\n }\n // Check if element exists in the page\n if (d3.select(options.elementId)[0][0] === null) {\n err = `Element ${options.elementId} is not present in the DOM`;\n }\n\n // hold onto the id\n this._elementId = options.elementId;\n this._renderer = options.renderer || 'svg'; // default to svg\n this.width = options.width || this.height;\n this.height = options.height || this.height;\n if (options.autolabels !== undefined && options.autolabels !== null) {\n this.autolabels = options.autolabels;\n }\n\n if (options.maxLabelLength) {\n // check if truncate label length has been passed in\n this.maxLabelLength = options.maxLabelLength;\n }\n\n // hold onto the token\n if (options.token) {\n this._token = options.token;\n }\n\n if (err) {\n throw new Error(err);\n }\n\n var chk = this.canDraw();\n\n if (chk.drawable) {\n this.update(clb);\n } else {\n // report the issues\n const errs = chk.issues.join(',');\n throw new Error(`Chart can not be drawn because: ${errs}`);\n }\n }\n }\n\n /**\n * Draw the chart based on any changes to data or specifications\n * Should be called after a user modifies\n * the dataset, query, mappings, chart specification or element size\n *\n * @example\n * dataset = {\"url\": \"...\", \"mappings\": {\"x\": {\"field\": \"STATE\"}, \"y\": {\"field\": \"POPULATION\"}}};\n * chart = new Cedar({ \"type\": \"bar\", \"dataset\": dataset });\n * chart.show({elementId: \"#chart\"});\n * chart.dataset.query.where = \"POPULATION>30000\";\n * chart.update();\n */\n update (clb) {\n if (this._view) {\n this.emit('update-start');\n }\n\n if (this._pendingXhr) {\n this._addToMethodQueue('update');\n } else {\n if (this._view) {\n // remove handlers\n // TODO Remove existing handlers\n this._remove(this._view);\n }\n\n try {\n // Creates the HTML Div and styling if not already created\n if (this._definition.tooltip) {\n this._createTooltip(this._definition.tooltip.id);\n }\n\n // Ensure we have required inputs or defaults\n let compiledMappings = specUtils.applyDefaultsToMappings(this._definition.dataset.mappings, this._definition.specification.inputs);\n\n let queryFromSpec = utils.mixin({}, this._definition.specification.query, this._definition.dataset.query);\n queryFromSpec = JSON.parse(utils.supplant(JSON.stringify(queryFromSpec), compiledMappings));\n\n // allow binding to query properties\n compiledMappings.query = queryFromSpec;\n\n // compile the template + mappings --> vega spec\n let spec = JSON.parse(utils.supplant(JSON.stringify(this._definition.specification.template), compiledMappings));\n\n // merge in user specified style overrides\n spec = utils.mergeRecursive(spec, this._definition.override);\n\n // if the spec has a url in the data node, delete it TODO: need to readress this.\n if (spec.data[0].url) {\n delete spec.data[0].url;\n }\n\n if (this._definition.dataset.data) {\n // create the data node using the passed in data\n spec.data[0].values = this._definition.dataset.data; // TODO: only works on first spec, need to address for multiple datasets.\n\n // Send to vega\n this._renderSpec(spec, clb);\n } else {\n // We need to fetch the data so....\n const url = requestUtils.createFeatureServiceRequest(this._definition.dataset, queryFromSpec);\n\n // create a callback closure to carry the spec\n const cb = (err, data) => {\n // Normalize error response\n if (!err && !!data.error) {\n err = new Error(data.error.message || data.error.details[0]);\n }\n // if no errors then continue...\n if (!err) {\n if (this._transform && typeof this._transform === 'function') {\n data = this._transform(data, this._definition.dataset);\n }\n // TODO add error handlers for xhr and AGS errors.\n spec.data[0].values = data;\n // send to vega\n this._renderSpec(spec, clb);\n } else {\n // optional callback\n if (!!clb && typeof clb === 'function') {\n clb(err, data);\n }\n }\n };\n\n // fetch the data from the service\n requestUtils.getJson(url, cb, this._timeout);\n }\n } catch (ex) {\n throw (ex);\n }\n }\n }\n\n /**\n * RENDER CHART FUNCTIONS\n *\n *\n * Render a compiled Vega specification using vega runtime\n */\n\n _renderSpec (spec, clb) {\n if (this.autolabels === true) {\n spec = this._placeLabels(spec);\n spec = this._placeaAxisTicks(spec);\n }\n // Use vega to parse the spec\n // It will handle the spec as an object or url\n vg.parse.spec(spec, (err, chartCtor) => {\n // create the view\n this._view = chartCtor({\n el: this._elementId,\n renderer: this._renderer\n });\n\n const width = this.width || parseInt(d3.select(this._elementId).style('width'), 10) || 500;\n const height = this.height || parseInt(d3.select(this._elementId).style('height'), 10) || 500;\n\n // render into the element\n this._view.width(width).height(height).update();\n\n // attach event proxies\n this._attach(this._view);\n\n if (this._view) {\n this.emit('update-end');\n }\n\n // expose errors\n if (!!clb && typeof clb === 'function') {\n clb(err, spec);\n }\n });\n }\n\n /**\n * AXIS TICK FUNCTIONS START HERE\n *\n *\n * Automatically determines axis title placement\n *\n * Calculates the maximum length of a tick label and adds padding\n */\n\n _placeLabels (spec) {\n try {\n const fields = {};\n const lengths = {};\n const inputs = [];\n // Get all inputs that may be axes\n for (let input in this._definition.dataset.mappings) {\n // check also if property is not inherited from prototype\n if (this._definition.dataset.mappings.hasOwnProperty(input)) {\n const field = this._definition.dataset.mappings[input].field;\n if (field) {\n inputs.push(input);\n fields[input] = field;\n lengths[input] = 0;\n }\n }\n }\n let length = 0;\n\n // find the max length value for each axis\n spec.data[0].values.features.forEach((feature) => {\n inputs.forEach((axis) => {\n length = (feature.attributes[fields[axis]] || '').toString().length;\n if (this.maxLabelLength) {\n // Need to make sure that the gap between title and labels isn't ridiculous\n length = length < (this.maxLabelLength + 1) ? length : this.maxLabelLength;\n }\n if (length > lengths[axis]) {\n lengths[axis] = length;\n }\n });\n });\n\n // Change each axis title offset based on longest value\n inputs.forEach((axis, index) => {\n let angle = 0;\n if (!!spec.axes && !!spec.axes[index]) {\n if (spec.axes[index].properties.labels.angle) {\n angle = spec.axes[index].properties.labels.angle.value;\n }\n if (spec.axes[index].type === 'y') {\n angle = 100 - angle;\n }\n if (this.maxLabelLength) {\n // Set max length of axes titles\n spec.axes[index].properties.labels.text = {'template': `{{ datum.data | truncate:\"${this.maxLabelLength}\"}}`};\n }\n // set title offset\n spec.axes[index].titleOffset = Math.abs(lengths[axis] * angle / 100 * 8) + 35;\n }\n });\n return spec;\n } catch (ex) {\n throw (ex);\n }\n }\n\n /**\n * Automatically determines number of axis tick marks\n *\n * Calculates the maximum length of a tick label and adds padding\n * TODO: remove expectation that there are both x,y axes\n */\n\n _placeaAxisTicks (spec) {\n if (spec.axes) {\n try {\n const width = this.width || parseInt(d3.select(this._elementId).style('width'), 10) || 500;\n const height = this.height || parseInt(d3.select(this._elementId).style('height'), 10) || 500;\n\n spec.axes[0].ticks = width / 100;\n if (spec.axes[1]) {\n spec.axes[1].ticks = height / 30;\n }\n } catch (ex) {\n throw (ex);\n }\n }\n return spec;\n }\n\n /**\n * TOOLTIP LOGIC HERE\n *\n * Instantiates the tooltip element and styling\n * @access private\n */\n _createTooltip (elem) {\n let tooltipDiv = document.getElementById(elem);\n\n // Check if tooltip has been created or not...\n if (tooltipDiv) {\n return tooltipDiv;\n }\n\n // TODO: remove inline CSS\n let style = document.createElement('style');\n style.type = 'text/css';\n style.innerHTML = '.cedar-tooltip {background-color: white; padding: 3px 10px; color: #333; margin: -30px 0 0 20px; position: absolute; z-index: 2000; font-size: 10px; border: 1px solid #BBB;} .cedar-tooltip .title {font-size: 13pt; font-weight: bold; } .cedar-tooltip .content {font-size: 10pt; } ';\n document.getElementsByTagName('head')[0].appendChild(style);\n\n tooltipDiv = document.createElement('div');\n tooltipDiv.className = 'cedar-tooltip';\n tooltipDiv.id = elem;\n tooltipDiv.cssText = 'display: none';\n // We need tooltip at the top of the page\n document.body.insertBefore(tooltipDiv, document.body.firstChild);\n\n this.on('mouseout', (event, data) => {\n this._updateTooltip(event, null);\n });\n this.on('mousemove', (event, data) => {\n this._updateTooltip(event, data);\n });\n return tooltipDiv;\n }\n\n /**\n * Places the tooltipe and fills in content\n *\n * @access private\n */\n _updateTooltip (event, data) {\n let cedartip = document.getElementById(this._definition.tooltip.id);\n if (!data) {\n cedartip.style.display = 'none';\n return;\n }\n cedartip.style.top = `${event.pageY}px`;\n cedartip.style.left = `${event.pageX}px`;\n cedartip.style.display = 'block';\n\n let content = `${this._definition.tooltip.title}${this._definition.tooltip.content}
`;\n\n cedartip.innerHTML = content.replace(/\\{(\\w+)\\}/g, (match, $1) => {\n return data[$1];\n });\n }\n\n /**\n * EVENT LOGIC HERE\n *\n *\n * Add a handler for the named event.\n * Events:\n * - mouseover\n * - mouseout\n * - click\n * - update-start\n * - update-end\n *\n *\n *\n * Callback from Cedar events\n * - callback Cedar~eventCallback\n * - param {Object} event - event response such as mouse location\n * - param {Object} data - chart data object\n *\n * @example\n * var chart = new Cedar({ ... });\n * chart.on('mouseover', function(event, data) {\n * console.log(\"Mouse Location:\", [event.offsetX, event.offsetY]);\n * console.log(\"Data value:\", data[Object.keys(data)[0]]);\n * });\n *\n * @param {String} eventName name of the event that invokes callback\n * @param {Cedar~eventCallback} callback - The callback that handles the event.\n */\n on (evtName, callback) {\n this._events.push({type: evtName, callback});\n }\n /**\n * Remove a hanlder for the named event\n */\n off (evtName, callback) {\n this._events.forEach((registeredEvent, index, object) => {\n if (registeredEvent.type === evtName && registeredEvent.callback === callback) {\n object.splice(index, 1);\n }\n });\n }\n\n /**\n * Trigger a callback\n * @param {string} eventName - [\"mouseover\",\"mouseout\",\"click\",\"update-start\",\"update-end\"]\n */\n emit (eventName) {\n if (!!this._view._handler._handlers[ eventName ] && !!this._view._handler._handlers[ eventName ][0]) {\n this._view._handler._handlers[ eventName ][0].handler();\n }\n }\n\n /**\n * Attach the generic proxy hanlders to the chart view\n * @access private\n */\n _attach (view) {\n view.on('mouseover', this._handler('mouseover'));\n view.on('mouseout', this._handler('mouseout'));\n view.on('mousemove', this._handler('mousemove'));\n view.on('click', this._handler('click'));\n view.on('update-start', this._handler('update-start'));\n view.on('update-end', this._handler('update-end'));\n }\n\n /**\n * Remove all event handlers from the view\n * @access private\n */\n _remove (view) {\n view.off('mouseover');\n view.off('mouseout');\n view.off('mousemove');\n view.off('click');\n view.off('update-start');\n view.off('update-end');\n }\n\n /**\n * Creates an entry in the method queue, executed\n * once a pending xhr is completed\n * @access private\n */\n _addToMethodQueue (name, args) {\n this._methodQueue.push({ method: name, args: args });\n }\n\n /**\n * empties the method queue by calling the queued methods\n * This helps build a more syncronous api, while still\n * doing async things in the code\n * @access private\n */\n _purgeMethodQueue () {\n if (this._methodQueue.length > 0) {\n this._methodQueue.forEach((action, index) => {\n this[action.method].apply(this, action.args);\n });\n }\n }\n\n /**\n * Generic event handler proxy\n * @access private\n */\n _handler (evtName) {\n // return a handler function w/ the events hash closed over\n const handler = (evt, item) => {\n this._events.forEach((registeredHandler) => {\n if (registeredHandler.type === evtName) {\n // invoke the callback with the data\n if (item) {\n registeredHandler.callback(evt, item.datum.attributes);\n } else {\n registeredHandler.callback(evt, null);\n }\n }\n });\n };\n return handler;\n }\n\n /**\n * SELECT LOGIC STARTS HERE\n *\n * Highlight marker based on attribute value\n *\n * @example\n * chart = new Cedar({...});\n * chart.select({key: 'ZIP_CODE', value: '20002'});\n *\n * @param {object} options - Object(key, value) to match. Calls hover on work\n * @returns {Array} items - array of chart objects that match the criteria\n */\n\n select (options) {\n let view = this._view;\n let items = view.model().scene().items[0].items[0].items;\n\n items.forEach((item) => {\n if (item.datum.attributes[options.key] === options.value) {\n if (item.hasPropertySet('hover')) {\n this._view.update({props: 'hover', items: item});\n }\n }\n });\n\n return items;\n }\n\n /**\n * Removes highlighted chart items\n *\n * If \"options\" are used, only clear specific items, otherwise clears all highlights.\n * @param {Object} options - Object(key, value) to match. Calls hover on mark\n * @returns {Array} items - array of chart objects that match the criteria, or null if all items.\n */\n\n clearSelection (options) {\n let view = this._view;\n\n if (!!options && !!options.key) {\n let items = view.model().scene().items[0].items[0].items;\n items.forEach((item) => {\n if (item.datum.attributes[options.key] === options.value) {\n this._view.update({props: 'update', items: item});\n }\n });\n return items;\n } else {\n // clear all\n this._view.update();\n return null;\n }\n }\n\n static getJson (url, callback, timeout) {\n return requestUtils.getJson(url, callback, timeout);\n }\n\n /**\n * Other now exposed utils!\n */\n static _validateMappings (inputs, mappings) {\n return utils.validateMappings(inputs, mappings);\n }\n static _validateData (data, mappings) {\n return utils.validateData(data, mappings);\n }\n static _createFeatureServiceRequest (dataset, queryFromSpec) {\n return requestUtils.createFeatureServiceRequest(dataset, queryFromSpec);\n }\n static _getMappingFieldName (mappingName, fieldName) {\n return utils.getMappingFieldName(mappingName, fieldName);\n }\n}\n"],"names":["mixin","source","let","args","i","length","d3.entries","forEach","p","key","value","mergeRecursive","obj1","obj2","hasOwnProperty","constructor","Object","Array","e","supplant","template","params","const","t","replace","a","b","r","getTokenValue","JSON","stringify","tokens","tokenName","tmpTokens","tokenNameParts","split","validateMappings","inputs","mappings","filter","input","required","name","validateData","data","missingInputs","features","isArray","Error","firstRow","attributes","fld","getMappingFieldName","field","push","mappingName","fieldName","defaultDefinition","dataset","query","defaultQuery","where","returnGeometry","returnDistinctValues","returnIdsOnly","returnCountOnly","outFields","sqlFormat","f","applyDefaultsToMappings","errs","join","serializeQueryParams","str","param","val","encodeURIComponent","queryString","getJson","url","callback","timeout","cb","err","response","parse","responseText","uri","d3.xhr","on","xhr","ontimeout","onload","header","post","get","createFeatureServiceRequest","queryFromSpec","mergedQuery","bbox","geometry","bboxArr","xmin","ymin","xmax","ymax","inSR","groupByFieldsForStatistics","group","outStatistics","count","orderByFields","statisticType","onStatisticField","outStatisticFieldName","sort","token","utils","specUtils","requestUtils","baseUrl","src","cdnProtocol","cdnUrl","window","document","currentScript","substr","lastIndexOf","location","protocol","Cedar","options","this","version","spec","opts","chartTypes","width","undefined","height","autolabels","maxLabelLength","_events","_definition","_view","_tooltip","_transform","_methodQueue","_timeout","_pendingXhr","definition","this$1","_purgeMethodQueue","override","_getSpecificationUrl","type","specification","tooltip","title","content","transform","prototypeAccessors","id","Date","now","indexOf","canDraw","drawable","show","clb","_addToMethodQueue","elementId","d3.select","_elementId","_renderer","renderer","_token","chk","issues","update","emit","_remove","_createTooltip","compiledMappings","values","_renderSpec","error","message","details","ex","_placeLabels","_placeaAxisTicks","vg.parse","chartCtor","el","parseInt","style","_attach","fields","lengths","feature","axis","toString","index","angle","axes","properties","labels","text","titleOffset","Math","abs","ticks","elem","tooltipDiv","getElementById","createElement","innerHTML","getElementsByTagName","appendChild","className","cssText","body","insertBefore","firstChild","event","_updateTooltip","cedartip","display","top","left","match","$1","evtName","off","registeredEvent","object","splice","eventName","_handler","_handlers","handler","view","method","action","apply","evt","item","registeredHandler","datum","select","items","model","scene","hasPropertySet","props","clearSelection","_validateMappings","_validateData","_createFeatureServiceRequest","_getMappingFieldName"],"mappings":"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"} \ No newline at end of file diff --git a/dist/charts/bar-horizontal.json b/dist/charts/bar-horizontal.json new file mode 100644 index 00000000..44ad9cf3 --- /dev/null +++ b/dist/charts/bar-horizontal.json @@ -0,0 +1,119 @@ +{ + "inputs": [ + { "name": "x", "type": [ "numeric", "string" ], "required": true }, + { "name": "y", "type": [ "string" ], "required": true } + ], + "query": { + "orderByFields": "{x.field} DESC", + "groupByFieldsForStatistics": "{y.field}", + "outStatistics": [{ + "statisticType": "sum", + "onStatisticField": "{x.field}", + "outStatisticFieldName": "{x.field}" + }] + }, + "template":{ + "padding": "strict", + "axes": [ + { + "type": "x", + "scale": "x", + "titleOffset": 45, + "title": "{x.label}", + "tickPadding": 10, + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1.5} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "angle": {"value": 0}, + "baseline": {"value": "middle"} + } + } + }, + { + "type": "y", + "scale": "y", + "titleOffset": 25, + "title": "{y.label}", + "padding": 0.25, + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1.5} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "angle": {"value": 0}, + "baseline": {"value": "middle"} + } + } + } + ], + "data": [ + { + "name": "table", + "format": {"property": "features"} + } + ], + "marks": [ + { + "from": {"data": "table"}, + "properties": { + "enter": { + "height": {"band": true, "offset": -1, "scale": "y"}, + "y": {"scale": "y", "field": "attributes.{y.field}"}, + "x2": {"scale": "x", "field": "attributes.{x.field}"}, + "x": {"scale": "x", "value": 0 } + }, + "hover": { + "fill": {"value": "#29b6ea"} + }, + "update": { + "fill": {"value": "#0079c1"} + } + }, + "type": "rect" + } + ], + "scales": [ + { + "domain": { + "data": "table", + "field": "attributes.{y.field}" + }, + "name": "y", + "range": "height", + "type": "ordinal", + "padding": 0.25 + }, + { + "domain": { + "data": "table", + "field": "attributes.{x.field}" + }, + "name": "x", + "nice": true, + "range": "width" + } + ] + } +} \ No newline at end of file diff --git a/dist/charts/bar.json b/dist/charts/bar.json new file mode 100644 index 00000000..e977dcd2 --- /dev/null +++ b/dist/charts/bar.json @@ -0,0 +1,108 @@ +{ + "inputs": [ + { "name": "x", "type": [ "string" ], "required": true }, + { "name": "y", "type": [ "numeric" ], "required": true } + ], + "query": {}, + "template":{ + "padding": "strict", + "axes": [ + { + "type": "x", + "scale": "x", + "titleOffset": 45, + "title": "{x.label}", + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1.5} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "angle": {"value": -50}, + "align": {"value": "right"}, + "baseline": {"value": "middle"} + } + } + }, + { + "type": "y", + "scale": "y", + "titleOffset": 45, + "title": "{y.label}", + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1.5} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"} + } + } + } + ], + "data": [ + { + "name": "table", + "format": {"property": "features"} + } + ], + "marks": [ + { + "from": {"data": "table"}, + "properties": { + "enter": { + }, + "update": { + "width": {"band": true, "offset": -1, "scale": "x"}, + "x": {"field": "attributes.{x.field}", "scale": "x"}, + "y": {"field": "attributes.{y.field}", "scale": "y"}, + "y2": {"scale": "y", "value": 0 }, + "fill": {"value": "#0079c1"} + }, + "hover": { + "fill": {"value": "#29b6ea"} + } + }, + "type": "rect" + } + ], + "scales": [ + { + "domain": { + "data": "table", + "field": "attributes.{x.field}" + }, + "name": "x", + "range": "width", + "type": "ordinal", + "padding": 0.25 + }, + { + "domain": { + "data": "table", + "field": "attributes.{y.field}" + }, + "name": "y", + "nice": true, + "range": "height" + } + ] + } +} \ No newline at end of file diff --git a/dist/charts/bubble.json b/dist/charts/bubble.json new file mode 100644 index 00000000..f799086d --- /dev/null +++ b/dist/charts/bubble.json @@ -0,0 +1,161 @@ +{ + "inputs": [ + {"name":"x","type":["numeric"], "required":true}, + {"name":"y","type":["numeric"], "required":true}, + {"name":"size","type":["numeric"], "default": 100, "required":false} + ], + "template":{ + "padding": "strict", + "data": [ + { + "name": "table", + "format": { + "property": "features" + } + } + ], + "scales": [ + { + "name": "x", + "nice": true, + "range": "width", + "domain": { + "data": "table", + "field": "attributes.{x.field}" + } + }, + { + "name": "y", + "nice": true, + "range": "height", + "domain": { + "data": "table", + "field": "attributes.{y.field}" + } + }, + { + "name": "size", + "type": "sqrt", + "domain": { + "data": "table", + "field": "attributes.{size.field}" + }, + "range": [0,2000] + } + ], + "axes": [ + { + "type": "x", + "scale": "x", + "offset": 5, + "ticks": 5, + "title": "{x.label}", + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "angle": {"value": 0}, + "fontSize": {"value": 14}, + "align": {"value": "left"}, + "baseline": {"value": "middle"}, + "dx": {"value": 3} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1.5} + } + } + }, + { + "type": "y", + "scale": "y", + "offset": 5, + "ticks": 5, + "title": "{y.label}", + "titleOffset": 50, + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "angle": {"value": 0}, + "fontSize": {"value": 14}, + "align": {"value": "right"} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1.5} + } + } + } + ], + "legends": [ + { + "title": "{size.label}", + "offset": 0, + "size": "size", + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "bold"} + }, + "symbols": { + "strokeWidth": {"value": 2}, + "stroke": {"value": "#0079c1"}, + "fill": { "value": "#fff" }, + "fillOpacity": {"value": 0.4 } + } + } + } + ], + "marks": [ + { + "type": "symbol", + "from": { + "data": "table" + }, + "properties": { + "enter": { + "x": { + "scale": "x", + "field": "attributes.{x.field}" + }, + "y": { + "scale": "y", + "field": "attributes.{y.field}" + }, + "strokeWidth": {"value": 2}, + "fillOpacity": {"value": 0.4 }, + "size": { + "scale": "size", + "field": "attributes.{size.field}" + } + }, + "update": { + "fill": { "value": "#fff" }, + "stroke": {"value": "#0079c1"} + }, + "hover": { + "fill": {"value": "#0079c1"}, + "fillOpacity": {"value": 0.6 }, + "stroke": {"value": "#0079c1"} + } + } + } + ] + } +} \ No newline at end of file diff --git a/dist/charts/grouped.json b/dist/charts/grouped.json new file mode 100644 index 00000000..4b37059f --- /dev/null +++ b/dist/charts/grouped.json @@ -0,0 +1,232 @@ +{ + "inputs": [ + { + "name": "x", + "required": true, + "type": [ + "numeric", + "string" + ] + }, + { + "name": "group", + "required": true, + "type": [ + "string" + ] + } + ], + "query": {}, + "template": { + "axes": [ + { + "properties": { + "axis": { + "stroke": { + "value": "#dbdad9" + }, + "strokeWidth": { + "value": 1.5 + } + }, + "labels": { + "align": { + "value": "right" + }, + "angle": { + "value": -50 + }, + "baseline": { + "value": "middle" + }, + "fill": { + "value": "#999" + } + }, + "ticks": { + "stroke": { + "value": "#dbdad9" + } + }, + "title": { + "fill": { + "value": "#999" + }, + "fontSize": { + "value": 15 + }, + "fontWeight": { + "value": "normal" + } + } + }, + "scale": "cat", + "tickPadding": 8, + "tickSize": 0, + "type": "x" + }, + { + "grid": true, + "layer": "back", + "properties": { + "axis": { + "stroke": { + "value": "#dbdad9" + }, + "strokeWidth": { + "value": 1.5 + } + }, + "labels": { + "fill": { + "value": "#999" + } + }, + "ticks": { + "stroke": { + "value": "#dbdad9" + } + }, + "title": { + "fill": { + "value": "#999" + }, + "fontSize": { + "value": 15 + }, + "fontWeight": { + "value": "normal" + } + } + }, + "scale": "val", + "type": "y" + } + ], + "data": [ + { + "format": { + "property": "features" + }, + "name": "table", + "transform": [ + { + "fields": "{x.field}", + "output": { + "key": "group", + "value": "count" + }, + "type": "fold" + } + ] + } + ], + "legends": [ + { + "fill": "color", + "title": "{x.label}" + } + ], + "marks": [ + { + "from": { + "data": "table", + "transform": [ + { + "groupby": [ + "attributes.{group.field}" + ], + "type": "facet" + } + ] + }, + "marks": [ + { + "name": "bars", + "properties": { + "enter": { + "fill": { + "field": "group", + "scale": "color" + }, + "width": { + "band": true, + "scale": "pos" + }, + "x": { + "field": "group", + "scale": "pos" + }, + "y": { + "field": "count", + "scale": "val" + }, + "y2": { + "scale": "val", + "value": 0 + } + } + }, + "type": "rect" + } + ], + "properties": { + "enter": { + "height": { + "band": true, + "scale": "cat" + }, + "x": { + "field": "key", + "scale": "cat" + } + } + }, + "scales": [ + { + "domain": { + "field": "group" + }, + "name": "pos", + "range": "height", + "type": "ordinal" + } + ], + "type": "group" + } + ], + "padding": "strict", + "scales": [ + { + "domain": { + "data": "table", + "field": "attributes.{group.field}" + }, + "name": "cat", + "padding": 0.2, + "range": "width", + "type": "ordinal" + }, + { + "domain": { + "data": "table", + "field": "count" + }, + "name": "val", + "nice": true, + "range": "height", + "round": true, + "type": "linear" + }, + { + "domain": { + "data": "table", + "field": "group" + }, + "name": "color", + "range": "category20", + "type": "ordinal" + } + ] + } +} diff --git a/dist/charts/pie.json b/dist/charts/pie.json new file mode 100644 index 00000000..7c9c4c54 --- /dev/null +++ b/dist/charts/pie.json @@ -0,0 +1,79 @@ +{ + "inputs": [ + {"name": "y", "type": ["numeric","string"], "required": true}, + {"name": "label", "type": ["string"], "required": false}, + {"name": "radius", "type": ["numeric"], "default": 200, "required": false} + ], + "template":{ + "padding": "strict", + "data": [ + { + "name": "table", + "format": { + "property": "features" + }, + "transform": [ + {"type": "pie", "field": "attributes.{y.field}"}, + {"type": "formula", "field": "hyp", "expr": "{radius}"}, + {"type": "formula", "field": "theta", "expr": "datum.layout_start + 0.5 *(datum.layout_end - datum.layout_start) - 1.57079633"}, + {"type": "formula", "field": "x", "expr": "datum.hyp * cos(datum.theta)"}, + {"type": "formula", "field": "y", "expr": "datum.hyp * sin(datum.theta)"} + ] + } + ], + "scales": [ + { + "name": "r", + "type": "sqrt", + "domain": {"data": "table", "field": "attributes.{y.field}"} + }, + { + "name": "color", + "type": "ordinal", + "domain": { + "data": "table", + "field": "attributes.{y.field}" + }, + "range": "category10" + } + ], + "marks": [ + { + "type": "arc", + "from": {"data": "table"}, + "properties": { + "enter": { + "x": {"group": "width"}, + "y": {"group": "height"}, + "startAngle": {"field": "layout_start"}, + "endAngle": {"field": "layout_end"}, + "outerRadius": {"value": "{radius}"}, + "stroke": {"value": "#fff"} + }, + "update": { + "fill": {"value": "#0079c1"} + }, + "hover": { + "fill": {"value": "#29b6ea"} + } + } + }, + { + "type": "text", + "from": {"data": "table"}, + "properties": { + "enter": { + "fill": {"value": "#fff"}, + "y": {"field": "y", "mult": 0.6}, + "x": {"field": "x", "mult": 0.6}, + "fill": {"value": "#fff"}, + "align": {"value": "center"}, + "baseline": {"value": "middle"}, + "text": {"field": "attributes.{label.field}"} + } + } + } + ] + } + +} \ No newline at end of file diff --git a/dist/charts/scatter.json b/dist/charts/scatter.json new file mode 100644 index 00000000..9942207c --- /dev/null +++ b/dist/charts/scatter.json @@ -0,0 +1,165 @@ +{ + "inputs":[ + {"name":"x","type":["numeric"], "required":true}, + {"name":"y","type":["numeric"], "required":true}, + {"name":"color","type":["string"], "default": "#0079c1", "required":false} + ], + "template":{ + "padding": "strict", + "data": [ + { + "name": "table", + "format": { + "property": "features" + } + } + ], + "scales": [ + { + "name": "x", + "nice": true, + "range": "width", + "domain": { + "data": "table", + "field": "attributes.{x.field}" + } + }, + { + "name": "y", + "nice": true, + "range": "height", + "domain": { + "data": "table", + "field": "attributes.{y.field}" + } + }, + { + "name": "c", + "type": "ordinal", + "domain": { + "data": "table", + "field": "attributes.{color.field}" + }, + "range": "category10" + } + ], + "axes": [ + { + "type": "x", + "scale": "x", + "title": "{x.label}", + "tickPadding": 10, + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1.5} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "angle": {"value": 0}, + "fontSize": {"value": 14}, + "align": {"value": "center"}, + "baseline": {"value": "middle"} + } + } + }, + { + "type": "y", + "scale": "y", + "offset": 5, + "ticks": 5, + "title": "{y.label}", + "titleOffset": 50, + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "angle": {"value": 0}, + "fontSize": {"value": 14}, + "align": {"value": "right"} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1.5} + } + } + } + ], + "legends": [ + { + "fill": "c", + "title": "{color.label} ", + "offset": 0, + "properties": { + "symbols": { + "fillOpacity": { + "value": 0.5 + }, + "stroke": { + "value": "transparent" + } + } + } + } + ], + "marks": [ + { + "type": "symbol", + "from": { + "data": "table" + }, + "properties": { + "enter": { + "x": { + "scale": "x", + "field": "attributes.{x.field}" + }, + "y": { + "scale": "y", + "field": "attributes.{y.field}" + }, + "fill": { + "scale": "c", + "field": "attributes.{color.field}" + }, + "fillOpacity": { + "value": 0.5 + } + }, + "update": { + "size": { + "value": 100 + }, + "stroke": { + "value": "transparent" + } + }, + "hover": { + "size": { + "value": 300 + }, + "stroke": { + "value": "white" + } + } + } + } + ] + } + +} \ No newline at end of file diff --git a/dist/charts/sparkline.json b/dist/charts/sparkline.json new file mode 100644 index 00000000..cda11e2c --- /dev/null +++ b/dist/charts/sparkline.json @@ -0,0 +1,41 @@ +{ + "inputs": [ + { "name": "x", "type": [ "datetime" ], "required": true }, + { "name": "y", "type": [ "number" ], "required": true } + ], + "template":{ + "data": [{ + "name": "table", + "format": {"type": "json", "parse": {"attributes.{x.field}":"date"}} + }], + "padding": {"top": 0, "left": 0, "bottom": 0, "right": 0}, + "scales": [ + { + "name": "x", + "type": "time", + "range": "width", + "zero": false, + "domain": {"data": "table", "field": "attributes.{x.field}"} + }, + { + "name": "y", + "type": "linear", + "range": "height", + "zero": false, + "domain": {"data": "table", "field": "attributes.{y.field}"} + } + ], + "marks": [{ + "type": "line", + "from": {"data": "table"}, + "properties": { + "enter": { + "x": {"scale": "x", "field": "attributes.{x.field}"}, + "y": {"scale": "y", "field": "attributes.{y.field}"}, + "stroke": {"value": "#f00"}, + "strokeWidth": {"value": 1} + } + } + }] + } +} \ No newline at end of file diff --git a/dist/charts/time-trendline.json b/dist/charts/time-trendline.json new file mode 100644 index 00000000..2f67b981 --- /dev/null +++ b/dist/charts/time-trendline.json @@ -0,0 +1,116 @@ +{ + "inputs":[ + {"name":"time","type":["time"], "required":true}, + {"name":"value","type":["numeric"], "required":true}, + {"name":"trendline","type":["numeric"], "required":true} + ], + "template":{ + "padding": "strict", + "data": [ + { + "name": "table", + "url":"{data}&orderByFields={time.field}", + "format": {"type": "json", "property": "features", "parse": {"attributes.{time.field}":"date"}} + }, + { + "name": "exports", + "source": "table", + "transform": [ + {"type": "formula", "field": "export", "expr": "datum"} + ] + } + ], + "scales": [ + { + "name": "x", + "type": "time", + "range": "width", + "nice": "month", + "zero": false, + "domain": {"data": "table", "field": "attributes.{time.field}"} + }, + { + "name": "y", + "type": "linear", + "range": "height", + "nice": true, + "domain": {"data": "table", "field": "attributes.{value.field}"} + } + ], + "axes": [ + { + "type": "x", + "scale": "x", + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "ticks": { + "strokeWidth" : {"value" :0} + }, + "labels": { + "fill": {"value": "#999"}, + "fontSize": {"value": 13} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 0} + } + } + }, + { + "type": "y", + "scale": "y", + "ticks": 5, + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "ticks": { + "strokeWidth" : {"value" :0} + }, + "labels": { + "fill": {"value": "#999"}, + "fontSize": {"value": 13} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 0} + } + } + } + ], + "marks": [ + { + "type": "line", + "from": {"data": "table"}, + "properties": { + "enter": { + "x": {"scale": "x", "field": "attributes.{time.field}"}, + "y": {"scale": "y", "field": "attributes.{value.field}"}, + "stroke": {"value": "#0079c1"}, + "strokeWidth" : { "value" : 3} + } + } + }, + { + "type": "line", + "from": {"data": "table"}, + "properties": { + "enter": { + "x": {"scale": "x", "field": "attributes.{time.field}"}, + "y": {"scale": "y", "field": "attributes.{trendline.field}"}, + "stroke": {"value": "#000000"}, + "strokeWidth" : { "value" : 3}, + "strokeDash" : { "value" : [7, 2]} + } + } + } + + ] + } +} \ No newline at end of file diff --git a/dist/charts/time.json b/dist/charts/time.json new file mode 100644 index 00000000..818e7f5b --- /dev/null +++ b/dist/charts/time.json @@ -0,0 +1,122 @@ +{ + "inputs":[ + {"name":"time","type":["time"], "required":true}, + {"name":"value","type":["numeric"], "required":true} + ], + "template":{ + "padding": "strict", + "data": [ + { + "name": "table", + "url":"{data}&orderByFields={time.field}", + "format": {"type": "json", "property": "features", "parse": {"attributes.{time.field}":"date"}} + }, + { + "name": "exports", + "source": "table", + "transform": [ + {"type": "formula", "field": "export", "expr": "datum"} + ] + } + ], + "scales": [ + { + "name": "x", + "type": "time", + "range": "width", + "zero": false, + "domain": {"data": "table", "field": "attributes.{time.field}"} + }, + { + "name": "y", + "type": "linear", + "range": "height", + "nice": true, + "domain": {"data": "table", "field": "attributes.{value.field}"} + } + ], + "axes": [ + { + "type": "x", + "scale": "x", + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "fontSize": {"value": 13} + }, + "axis": { + "stroke": {"value": "#dbdad9"}, + "strokeWidth": {"value": 1} + } + } + }, + { + "type": "y", + "scale": "y", + "ticks": 5, + "properties": { + "title": { + "fontSize": {"value": 15}, + "fill": {"value": "#999"}, + "fontWeight": {"value": "normal"} + }, + "ticks": { + "stroke": {"value": "#dbdad9"} + }, + "labels": { + "fill": {"value": "#999"}, + "fontSize": {"value": 13} + }, + "axis": { + "stroke": {"value": "#dbdad9"} + } + } + } + ], + "marks": [ + { + "type": "symbol", + "from": {"data": "table"}, + "properties": { + "enter": { + "x": {"scale": "x", "field": "attributes.{time.field}"}, + "y": {"scale": "y", "field": "attributes.{value.field}"}, + "stroke": {"value": "#0079c1"}, + "fill": {"value": "#0079c1"}, + "size": {"value": 20}, + "fillOpacity": { + "value": 0.8 + }, + "hover": { + "fill": {"value": "#0079c1"}, + "size": {"value": 25} + }, + "update": { + "fill": {"value": "#f00"} + } + } + } + }, + { + "type": "line", + "from": {"data": "table"}, + "properties": { + "enter": { + "x": {"scale": "x", "field": "attributes.{time.field}"}, + "y": {"scale": "y", "field": "attributes.{value.field}"}, + "y2": {"scale": "y", "value": 0}, + "stroke": {"value": "#0079c1"} + } + } + } + ] + } +} \ No newline at end of file