diff --git a/dist/cedar.js b/dist/cedar.js new file mode 100644 index 00000000..7a0c9818 --- /dev/null +++ b/dist/cedar.js @@ -0,0 +1,1372 @@ +/** +* arcgis-cedar - v0.9.1 - Thu Mar 02 2017 08:51:29 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.9.1"; + +/** + * 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; + } +} + +/** + * Convert datasets to dataset + */ +function convertDatasetsToDataset (datasets, series, chartType, dataset) { + // console.log('Datasets and dataset are:', datasets, dataset); + if (!dataset) { + dataset = { + query: this.defaultQuery() + }; + } + // Mappings held here + var mappings = {}; + // Queries held here + var queries = []; + // Urls held here + var urls = []; + // Data held here + var data = []; + + datasets.forEach(function (dtst) { + // Push queries data and urls first + if (dtst.query) { + queries.push(dtst.query); + } + if (dtst.url) { + urls.push(dtst.url); + } + if (dtst.data) { + data.push(dtst.data); + } + // Construct mappings + // Grouped bar chart here + if (chartType === 'grouped') { + if (!mappings.group) { + mappings.group = series[0].category; + } + if (!mappings.x) { + mappings.x = { + field: [], + label: series[0].value.label + }; + } + if (series.length > 1) { + series.forEach(function (attr) { + mappings.x.field.push(("attributes." + (attr.value.field))); + }); + } else { + mappings.x.field.push(("attributes." + (series[0].value.field))); + } + + // Bubble Chart starts here + } else if (chartType === 'bubble') { + mappings.x = series[0].category; + mappings.y = series[0].value; + mappings.size = series[0].size; + + // Scatter plot starts here + } else if (chartType === 'scatter') { + mappings.x = series[0].category; + mappings.y = series[0].value; + mappings.color = series[0].color; + + // Pie Chart starts here + } else if (chartType === 'pie') { + mappings.label = series[0].category; + mappings.y = series[0].value; + mappings.radius = series[0].radius; + + // Bar horizontal starts here + } else if (chartType === 'bar-horizontal') { + mappings.y = series[0].category; + mappings.x = series[0].value; + + // Timeline chart starts here + } else if (chartType === 'time') { + mappings.time = series[0].category; + mappings.value = series[0].value; + + // time-trendline chart starts here + } else if (chartType === 'time-trendline') { + mappings.time = series[0].category; + mappings.value = series[0].value; + mappings.trendline = series[0].trendline; + + // X Y only charts here + } else { + mappings.x = series[0].category; + mappings.y = series[0].value; + } + }); + + var builtDataset = { + query: convertQueries(queries, dataset.query), + mappings: mappings + }; + if (data.length > 0) { + builtDataset.data = data[0]; + } + + if (urls.length > 0) { + builtDataset.url = convertUrls(urls); + } + + return builtDataset; +} + +/** + * Convert over query + */ +function convertQueries (queries, defaultQuery) { + if (queries.length > 1) { + console.warn('Warning, currently multiple queries is not supported. Reverting to default.', queries); + return defaultQuery; + } + return queries[0] ? queries[0] : defaultQuery; // Might not have a query passed in so check and if it hasn't then return default query +} + +/** + * Convert over URLs + */ +function convertUrls (urls) { + if (urls.length > 1) { + console.warn('Warning, currently multiple URLS are not supported. Using first url', urls); + return urls[0]; + } + return urls[0]; +} + +var specUtils = { + defaultDefinition: defaultDefinition, + defaultQuery: defaultQuery, + applyDefaultsToMappings: applyDefaultsToMappings, + convertDatasetsToDataset: convertDatasetsToDataset +}; + +/** + * 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' + this._chartType = opts.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; + } + + // Allow datasets to be passed in + if (opts.datasets && Array.isArray(opts.datasets)) { + this._definition.datasets = opts.datasets; + } + + // Allow series to be passed in + if (opts.series && Array.isArray(opts.series)) { + this._definition.series = opts.series; + } + + /** + * 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: {},datasets: {},series: {},specification: {},override: {},tooltip: {},transform: {} }; + +/** + * Properties + */ +// Dataset - old api +prototypeAccessors.dataset.get = function () { + return this._definition.dataset; +}; +prototypeAccessors.dataset.set = function (val) { + this._definition.dataset = val; +}; + +// Datasets - new api +prototypeAccessors.datasets.get = function () { + return this._definition.datasets; +}; +prototypeAccessors.datasets.set = function (val) { + this._definition.datasets = val; +}; + +// Series - new api +prototypeAccessors.series.get = function () { + return this._definition.series; +}; +prototypeAccessors.series.set = function (val) { + this._definition.series = 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 { + if (this._definition.datasets && this._definition.series) { + this._definition.dataset = specUtils.convertDatasetsToDataset(this._definition.datasets, this._definition.series, this._chartType, this._definition.dataset); + if (!this._definition.tooltip) { + this.tooltip = { + 'title': ("{" + (this._definition.series[0].category.field) + "}"), + 'content': ("{" + (this._definition.series[0].value.field) + "}") + }; + } + } + + // 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); +}; +// TODO: remove once we have a better way to unit test +Cedar._convertDatasetsToDataset = function _convertDatasetsToDataset (datasets, dataset, chartType) { + return specUtils.convertDatasetsToDataset(datasets, dataset, chartType); +}; + +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..6b8329b2 --- /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\n/**\n * Convert datasets to dataset\n */\nexport function convertDatasetsToDataset (datasets, series, chartType, dataset) {\n // console.log('Datasets and dataset are:', datasets, dataset);\n if (!dataset) {\n dataset = {\n query: this.defaultQuery()\n };\n }\n // Mappings held here\n const mappings = {};\n // Queries held here\n const queries = [];\n // Urls held here\n const urls = [];\n // Data held here\n const data = [];\n\n datasets.forEach((dtst) => {\n // Push queries data and urls first\n if (dtst.query) {\n queries.push(dtst.query);\n }\n if (dtst.url) {\n urls.push(dtst.url);\n }\n if (dtst.data) {\n data.push(dtst.data);\n }\n // Construct mappings\n // Grouped bar chart here\n if (chartType === 'grouped') {\n if (!mappings.group) {\n mappings.group = series[0].category;\n }\n if (!mappings.x) {\n mappings.x = {\n field: [],\n label: series[0].value.label\n };\n }\n if (series.length > 1) {\n series.forEach((attr) => {\n mappings.x.field.push(`attributes.${attr.value.field}`);\n });\n } else {\n mappings.x.field.push(`attributes.${series[0].value.field}`);\n }\n\n // Bubble Chart starts here\n } else if (chartType === 'bubble') {\n mappings.x = series[0].category;\n mappings.y = series[0].value;\n mappings.size = series[0].size;\n\n // Scatter plot starts here\n } else if (chartType === 'scatter') {\n mappings.x = series[0].category;\n mappings.y = series[0].value;\n mappings.color = series[0].color;\n\n // Pie Chart starts here\n } else if (chartType === 'pie') {\n mappings.label = series[0].category;\n mappings.y = series[0].value;\n mappings.radius = series[0].radius;\n\n // Bar horizontal starts here\n } else if (chartType === 'bar-horizontal') {\n mappings.y = series[0].category;\n mappings.x = series[0].value;\n\n // Timeline chart starts here\n } else if (chartType === 'time') {\n mappings.time = series[0].category;\n mappings.value = series[0].value;\n\n // time-trendline chart starts here\n } else if (chartType === 'time-trendline') {\n mappings.time = series[0].category;\n mappings.value = series[0].value;\n mappings.trendline = series[0].trendline;\n\n // X Y only charts here\n } else {\n mappings.x = series[0].category;\n mappings.y = series[0].value;\n }\n });\n\n const builtDataset = {\n query: convertQueries(queries, dataset.query),\n mappings\n };\n if (data.length > 0) {\n builtDataset.data = data[0];\n }\n\n if (urls.length > 0) {\n builtDataset.url = convertUrls(urls);\n }\n\n return builtDataset;\n}\n\n/**\n * Convert over query\n */\nfunction convertQueries (queries, defaultQuery) {\n if (queries.length > 1) {\n console.warn('Warning, currently multiple queries is not supported. Reverting to default.', queries);\n return defaultQuery;\n }\n return queries[0] ? queries[0] : defaultQuery; // Might not have a query passed in so check and if it hasn't then return default query\n}\n\n/**\n * Convert over URLs\n */\nfunction convertUrls (urls) {\n if (urls.length > 1) {\n console.warn('Warning, currently multiple URLS are not supported. Using first url', urls);\n return urls[0];\n }\n return urls[0];\n}\n\nconst specUtils = {\n defaultDefinition,\n defaultQuery,\n applyDefaultsToMappings,\n convertDatasetsToDataset\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 this._chartType = opts.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 // Allow datasets to be passed in\n if (opts.datasets && Array.isArray(opts.datasets)) {\n this._definition.datasets = opts.datasets;\n }\n\n // Allow series to be passed in\n if (opts.series && Array.isArray(opts.series)) {\n this._definition.series = opts.series;\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 // Dataset - old api\n get dataset () {\n return this._definition.dataset;\n }\n set dataset (val) {\n this._definition.dataset = val;\n }\n\n // Datasets - new api\n get datasets () {\n return this._definition.datasets;\n }\n set datasets (val) {\n this._definition.datasets = val;\n }\n\n // Series - new api\n get series () {\n return this._definition.series;\n }\n set series (val) {\n this._definition.series = 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 if (this._definition.datasets && this._definition.series) {\n this._definition.dataset = specUtils.convertDatasetsToDataset(this._definition.datasets, this._definition.series, this._chartType, this._definition.dataset);\n if (!this._definition.tooltip) {\n this.tooltip = {\n 'title': `{${this._definition.series[0].category.field}}`,\n 'content': `{${this._definition.series[0].value.field}}`\n };\n }\n }\n\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 // 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}
`;\n content += `

${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 // TODO: remove once we have a better way to unit test\n static _convertDatasetsToDataset (datasets, dataset, chartType) {\n return specUtils.convertDatasetsToDataset(datasets, dataset, chartType);\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..24eb479e --- /dev/null +++ b/dist/cedar.min.js @@ -0,0 +1,7 @@ +/** +* arcgis-cedar - v0.9.1 - Thu Mar 02 2017 08:51:30 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 r=[].concat(n),o=1;o0)throw new Error("Required Mappings Missing: "+i.join(","));return t}function f(t,e,i,n){n||(n={query:this.defaultQuery()});var r={},o=[],a=[],s=[];t.forEach(function(t){t.query&&o.push(t.query),t.url&&a.push(t.url),t.data&&s.push(t.data),"grouped"===i?(r.group||(r.group=e[0].category),r.x||(r.x={field:[],label:e[0].value.label}),e.length>1?e.forEach(function(t){r.x.field.push("attributes."+t.value.field)}):r.x.field.push("attributes."+e[0].value.field)):"bubble"===i?(r.x=e[0].category,r.y=e[0].value,r.size=e[0].size):"scatter"===i?(r.x=e[0].category,r.y=e[0].value,r.color=e[0].color):"pie"===i?(r.label=e[0].category,r.y=e[0].value,r.radius=e[0].radius):"bar-horizontal"===i?(r.y=e[0].category,r.x=e[0].value):"time"===i?(r.time=e[0].category,r.value=e[0].value):"time-trendline"===i?(r.time=e[0].category,r.value=e[0].value,r.trendline=e[0].trendline):(r.x=e[0].category,r.y=e[0].value)});var u={query:h(o,n.query),mappings:r};return s.length>0&&(u.data=s[0]),a.length>0&&(u.url=c(a)),u}function h(t,e){return t.length>1?(console.warn("Warning, currently multiple queries is not supported. Reverting to default.",t),e):t[0]?t[0]:e}function c(t){return t.length>1?(console.warn("Warning, currently multiple URLS are not supported. Using first url",t),t[0]):t[0]}function m(t){var e=[];for(var i in t)if(t.hasOwnProperty(i)){var n=t[i];"string"!=typeof n&&(n=JSON.stringify(n)),e.push(encodeURIComponent(i)+"="+encodeURIComponent(n))}var r=e.join("&");return r}function g(e,i,n){var r=function(t,n){t&&""===t.response?i(new Error("This service is taking too long to respond, unable to chart")):t?i(new Error("Error loading "+e+" with a response of: "+t.message)):i(null,JSON.parse(n.responseText))};if(e.length>2e3){var o=e.split("?");t.xhr(o[0]).on("beforesend",function(t){t.timeout=n,t.ontimeout=t.onload}).header("Content-Type","application/x-www-form-urlencoded").post(o[1],r)}else t.xhr(e).on("beforesend",function(t){t.timeout=n,t.ontimeout=t.onload}).get(r)}function v(t,e){var n=i({},l(),e);if(n.bbox){if(n.geometry)throw new Error("Dataset.query can not have both a geometry and a bbox specified");var r=n.bbox.split(",");delete n.bbox,n.geometry=JSON.stringify({xmin:r[0],ymin:r[2],xmax:r[1],ymax:r[3]}),n.inSR="4326"}!n.groupByFieldsForStatistics&&t.mappings.group&&(n.groupByFieldsForStatistics=t.mappings.group.field),!n.outStatistics&&t.mappings.count&&(n.orderByFields=t.mappings.count.field+"_SUM",n.outStatistics=JSON.stringify([{statisticType:"sum",onStatisticField:t.mappings.count.field,outStatisticFieldName:t.mappings.count.field+"_SUM"}])),t.mappings.sort&&(n.orderByFields=t.mappings.sort);var o=t.url+"/query?"+m(n);return t.token&&(o=o+"&token="+t.token),o}var _="0.9.1",y={mixin:i,supplant:r,mergeRecursive:n,getTokenValue:o,validateMappings:a,validateData:s,getMappingFieldName:u},b={defaultDefinition:d,defaultQuery:l,applyDefaultsToMappings:p,convertDatasetsToDataset:f},w={getJson:g,createFeatureServiceRequest:v},x=function(){var t,e="http:",i="//esri.github.io/cedar/js";return window&&window.document?(t=window.document.currentScript&&window.document.currentScript.src,t?t.substr(0,t.lastIndexOf("/")):(window.document.location?window.document.location.protocol:e)+i):e+i}(),S=function(t){var e=this;this.version=_;var i,n=t||{};if(this.baseUrl=x,this.chartTypes=["bar","bar-horizontal","bubble","grouped","pie","scatter","sparkline","time","time-trendline"],this.width=void 0,this.height=void 0,this.autolabels=!0,this.maxLabelLength=void 0,this._events=[],this._definition=b.defaultDefinition(),this._view=void 0,this._tooltip=void 0,this._transform=void 0,this._methodQueue=[],this._timeout=void 0,n.timeout&&(this._timeout=n.timeout),n.baseUrl&&(this.baseUrl=n.baseUrl),this._pendingXhr=!1,n.definition)if("object"==typeof n.definition)this._definition=n.definition;else{if("string"!=typeof n.definition)throw new Error("parameter definition must be an object or string (url)");this._pendingXhr=!0,w.getJson(n.definition,function(t,i){if(t)throw new Error("Error fetching definition object",t);e._pendingXhr=!1,e._definition=i,e._purgeMethodQueue()},this._timeout)}if(n.override&&(this._definition.override=n.override),this._chartType=n.type,i=this._getSpecificationUrl(n.type),n.specification&&(i=n.specification),i)if("object"==typeof i)this._definition.specification=i;else{if("string"!=typeof i)throw new Error("parameter specification must be an object or string (url)");this._pendingXhr=!0,this._pendingXhr=!0,w.getJson(i,function(t,i){if(t)throw new Error("Error fetching template object",t);e._pendingXhr=!1,e._definition.specification=i,e._purgeMethodQueue()},this._timeout)}if(n.dataset&&"object"==typeof n.dataset&&(n.dataset.query=y.mixin({},b.defaultQuery(),n.dataset.query),this._definition.dataset=n.dataset),n.datasets&&Array.isArray(n.datasets)&&(this._definition.datasets=n.datasets),n.series&&Array.isArray(n.series)&&(this._definition.series=n.series),n.tooltip&&"object"==typeof n.tooltip)this.tooltip=n.tooltip;else{var r=[];for(var o in this._definition.dataset.mappings)if(e._definition.dataset.mappings.hasOwnProperty(o)){var a=e._definition.dataset.mappings[o].field;void 0!==a&&null!==a&&r.push(a)}r.length>=2&&(this.tooltip={title:"{"+r[0]+"}",content:"{"+r[1]+"}"})}n.transform&&"function"==typeof n.transform&&(this._transform=n.transform)},E={dataset:{},datasets:{},series:{},specification:{},override:{},tooltip:{},transform:{}};return E.dataset.get=function(){return this._definition.dataset},E.dataset.set=function(t){this._definition.dataset=t},E.datasets.get=function(){return this._definition.datasets},E.datasets.set=function(t){this._definition.datasets=t},E.series.get=function(){return this._definition.series},E.series.set=function(t){this._definition.series=t},E.specification.get=function(){return this._definition.specification},E.specification.set=function(t){this._definition.specification=t},E.override.get=function(){return this._definition.override},E.override.set=function(t){this._definition.override=t},E.tooltip.get=function(){return this._definition.tooltip},E.tooltip.set=function(t){this._definition.tooltip=t,void 0!==this._definition.tooltip.id&&null!==this._definition.tooltip.id||(this._definition.tooltip.id="cedar-"+Date.now())},E.transform.get=function(){return this._transform},E.transform.set=function(t){this._transform=t},S.prototype._getSpecificationUrl=function(t){return this.chartTypes.indexOf(t)!==-1&&(t=this.baseUrl+"/charts/"+this.chartTypes[this.chartTypes.indexOf(t)]+".json"),t},S.prototype.canDraw=function(){return{drawable:!0,errs:[]}},S.prototype.show=function(e,i){if(this._pendingXhr)this._addToMethodQueue("show",[e,i]);else{var n;if(e.elementId||(n="Cedar.show requires options.elementId"),null===t.select(e.elementId)[0][0]&&(n="Element "+e.elementId+" is not present in the DOM"),this._elementId=e.elementId,this._renderer=e.renderer||"svg",this.width=e.width||this.height,this.height=e.height||this.height,void 0!==e.autolabels&&null!==e.autolabels&&(this.autolabels=e.autolabels),e.maxLabelLength&&(this.maxLabelLength=e.maxLabelLength),e.token&&(this._token=e.token),n)throw new Error(n);var r=this.canDraw();if(!r.drawable){var o=r.issues.join(",");throw new Error("Chart can not be drawn because: "+o)}this.update(i)}},S.prototype.update=function(t){var e=this;if(this._view&&this.emit("update-start"),this._pendingXhr)this._addToMethodQueue("update");else{this._view&&this._remove(this._view);try{this._definition.datasets&&this._definition.series&&(this._definition.dataset=b.convertDatasetsToDataset(this._definition.datasets,this._definition.series,this._chartType,this._definition.dataset),this._definition.tooltip||(this.tooltip={title:"{"+this._definition.series[0].category.field+"}",content:"{"+this._definition.series[0].value.field+"}"})),this._definition.tooltip&&this._createTooltip(this._definition.tooltip.id);var i=b.applyDefaultsToMappings(this._definition.dataset.mappings,this._definition.specification.inputs),n=y.mixin({},this._definition.specification.query,this._definition.dataset.query);n=JSON.parse(y.supplant(JSON.stringify(n),i)),i.query=n;var r=JSON.parse(y.supplant(JSON.stringify(this._definition.specification.template),i));if(r=y.mergeRecursive(r,this._definition.override),r.data[0].url&&delete r.data[0].url,this._definition.dataset.data)r.data[0].values=this._definition.dataset.data,this._renderSpec(r,t);else{var o=w.createFeatureServiceRequest(this._definition.dataset,n),a=function(i,n){!i&&n.error&&(i=new Error(n.error.message||n.error.details[0])),i?t&&"function"==typeof t&&t(i,n):(e._transform&&"function"==typeof e._transform&&(n=e._transform(n,e._definition.dataset)),r.data[0].values=n,e._renderSpec(r,t))};w.getJson(o,a,this._timeout)}}catch(t){throw t}}},S.prototype._renderSpec=function(i,n){var r=this;this.autolabels===!0&&(i=this._placeLabels(i),i=this._placeaAxisTicks(i)),e.parse.spec(i,function(e,o){r._view=o({el:r._elementId,renderer:r._renderer});var a=r.width||parseInt(t.select(r._elementId).style("width"),10)||500,s=r.height||parseInt(t.select(r._elementId).style("height"),10)||500;r._view.width(a).height(s).update(),r._attach(r._view),r._view&&r.emit("update-end"),n&&"function"==typeof n&&n(e,i)})},S.prototype._placeLabels=function(t){var e=this;try{var i={},n={},r=[];for(var o in this._definition.dataset.mappings)if(e._definition.dataset.mappings.hasOwnProperty(o)){var a=e._definition.dataset.mappings[o].field;a&&(r.push(o),i[o]=a,n[o]=0)}var s=0;return t.data[0].values.features.forEach(function(t){r.forEach(function(r){s=(t.attributes[i[r]]||"").toString().length,e.maxLabelLength&&(s=sn[r]&&(n[r]=s)})}),r.forEach(function(i,r){var o=0;t.axes&&t.axes[r]&&(t.axes[r].properties.labels.angle&&(o=t.axes[r].properties.labels.angle.value),"y"===t.axes[r].type&&(o=100-o),e.maxLabelLength&&(t.axes[r].properties.labels.text={template:'{{ datum.data | truncate:"'+e.maxLabelLength+'"}}'}),t.axes[r].titleOffset=Math.abs(n[i]*o/100*8)+35)}),t}catch(t){throw t}},S.prototype._placeaAxisTicks=function(e){if(e.axes)try{var i=this.width||parseInt(t.select(this._elementId).style("width"),10)||500,n=this.height||parseInt(t.select(this._elementId).style("height"),10)||500;e.axes[0].ticks=i/100,e.axes[1]&&(e.axes[1].ticks=n/30)}catch(t){throw t}return e},S.prototype._createTooltip=function(t){var e=this,i=document.getElementById(t);if(i)return i;var n=document.createElement("style");return n.type="text/css",n.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(n),i=document.createElement("div"),i.className="cedar-tooltip",i.id=t,i.cssText="display: none",document.body.insertBefore(i,document.body.firstChild),this.on("mouseout",function(t,i){e._updateTooltip(t,null)}),this.on("mousemove",function(t,i){e._updateTooltip(t,i)}),i},S.prototype._updateTooltip=function(t,e){var i=document.getElementById(this._definition.tooltip.id);if(!e)return void(i.style.display="none");i.style.top=t.pageY+"px",i.style.left=t.pageX+"px",i.style.display="block";var n=""+this._definition.tooltip.title+"
";n+="

"+this._definition.tooltip.content+"

",i.innerHTML=n.replace(/\{(\w+)\}/g,function(t,i){return e[i]})},S.prototype.on=function(t,e){this._events.push({type:t,callback:e})},S.prototype.off=function(t,e){this._events.forEach(function(i,n,r){i.type===t&&i.callback===e&&r.splice(n,1)})},S.prototype.emit=function(t){this._view._handler._handlers[t]&&this._view._handler._handlers[t][0]&&this._view._handler._handlers[t][0].handler()},S.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"))},S.prototype._remove=function(t){t.off("mouseover"),t.off("mouseout"),t.off("mousemove"),t.off("click"),t.off("update-start"),t.off("update-end")},S.prototype._addToMethodQueue=function(t,e){this._methodQueue.push({method:t,args:e})},S.prototype._purgeMethodQueue=function(){var t=this;this._methodQueue.length>0&&this._methodQueue.forEach(function(e,i){t[e.method].apply(t,e.args)})},S.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},S.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},S.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},S.getJson=function(t,e,i){return w.getJson(t,e,i)},S._validateMappings=function(t,e){return y.validateMappings(t,e)},S._validateData=function(t,e){return y.validateData(t,e)},S._createFeatureServiceRequest=function(t,e){return w.createFeatureServiceRequest(t,e)},S._getMappingFieldName=function(t,e){return y.getMappingFieldName(t,e)},S._convertDatasetsToDataset=function(t,e,i){return b.convertDatasetsToDataset(t,e,i)},Object.defineProperties(S.prototype,E),S}); +//# 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..4e7050f3 --- /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\n/**\n * Convert datasets to dataset\n */\nexport function convertDatasetsToDataset (datasets, series, chartType, dataset) {\n // console.log('Datasets and dataset are:', datasets, dataset);\n if (!dataset) {\n dataset = {\n query: this.defaultQuery()\n };\n }\n // Mappings held here\n const mappings = {};\n // Queries held here\n const queries = [];\n // Urls held here\n const urls = [];\n // Data held here\n const data = [];\n\n datasets.forEach((dtst) => {\n // Push queries data and urls first\n if (dtst.query) {\n queries.push(dtst.query);\n }\n if (dtst.url) {\n urls.push(dtst.url);\n }\n if (dtst.data) {\n data.push(dtst.data);\n }\n // Construct mappings\n // Grouped bar chart here\n if (chartType === 'grouped') {\n if (!mappings.group) {\n mappings.group = series[0].category;\n }\n if (!mappings.x) {\n mappings.x = {\n field: [],\n label: series[0].value.label\n };\n }\n if (series.length > 1) {\n series.forEach((attr) => {\n mappings.x.field.push(`attributes.${attr.value.field}`);\n });\n } else {\n mappings.x.field.push(`attributes.${series[0].value.field}`);\n }\n\n // Bubble Chart starts here\n } else if (chartType === 'bubble') {\n mappings.x = series[0].category;\n mappings.y = series[0].value;\n mappings.size = series[0].size;\n\n // Scatter plot starts here\n } else if (chartType === 'scatter') {\n mappings.x = series[0].category;\n mappings.y = series[0].value;\n mappings.color = series[0].color;\n\n // Pie Chart starts here\n } else if (chartType === 'pie') {\n mappings.label = series[0].category;\n mappings.y = series[0].value;\n mappings.radius = series[0].radius;\n\n // Bar horizontal starts here\n } else if (chartType === 'bar-horizontal') {\n mappings.y = series[0].category;\n mappings.x = series[0].value;\n\n // Timeline chart starts here\n } else if (chartType === 'time') {\n mappings.time = series[0].category;\n mappings.value = series[0].value;\n\n // time-trendline chart starts here\n } else if (chartType === 'time-trendline') {\n mappings.time = series[0].category;\n mappings.value = series[0].value;\n mappings.trendline = series[0].trendline;\n\n // X Y only charts here\n } else {\n mappings.x = series[0].category;\n mappings.y = series[0].value;\n }\n });\n\n const builtDataset = {\n query: convertQueries(queries, dataset.query),\n mappings\n };\n if (data.length > 0) {\n builtDataset.data = data[0];\n }\n\n if (urls.length > 0) {\n builtDataset.url = convertUrls(urls);\n }\n\n return builtDataset;\n}\n\n/**\n * Convert over query\n */\nfunction convertQueries (queries, defaultQuery) {\n if (queries.length > 1) {\n console.warn('Warning, currently multiple queries is not supported. Reverting to default.', queries);\n return defaultQuery;\n }\n return queries[0] ? queries[0] : defaultQuery; // Might not have a query passed in so check and if it hasn't then return default query\n}\n\n/**\n * Convert over URLs\n */\nfunction convertUrls (urls) {\n if (urls.length > 1) {\n console.warn('Warning, currently multiple URLS are not supported. Using first url', urls);\n return urls[0];\n }\n return urls[0];\n}\n\nconst specUtils = {\n defaultDefinition,\n defaultQuery,\n applyDefaultsToMappings,\n convertDatasetsToDataset\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 this._chartType = opts.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 // Allow datasets to be passed in\n if (opts.datasets && Array.isArray(opts.datasets)) {\n this._definition.datasets = opts.datasets;\n }\n\n // Allow series to be passed in\n if (opts.series && Array.isArray(opts.series)) {\n this._definition.series = opts.series;\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 // Dataset - old api\n get dataset () {\n return this._definition.dataset;\n }\n set dataset (val) {\n this._definition.dataset = val;\n }\n\n // Datasets - new api\n get datasets () {\n return this._definition.datasets;\n }\n set datasets (val) {\n this._definition.datasets = val;\n }\n\n // Series - new api\n get series () {\n return this._definition.series;\n }\n set series (val) {\n this._definition.series = 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 if (this._definition.datasets && this._definition.series) {\n this._definition.dataset = specUtils.convertDatasetsToDataset(this._definition.datasets, this._definition.series, this._chartType, this._definition.dataset);\n if (!this._definition.tooltip) {\n this.tooltip = {\n 'title': `{${this._definition.series[0].category.field}}`,\n 'content': `{${this._definition.series[0].value.field}}`\n };\n }\n }\n\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 // 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}
`;\n content += `

${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 // TODO: remove once we have a better way to unit test\n static _convertDatasetsToDataset (datasets, dataset, chartType) {\n return specUtils.convertDatasetsToDataset(datasets, dataset, chartType);\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","convertDatasetsToDataset","datasets","series","chartType","this","queries","urls","dtst","url","group","category","x","label","attr","y","size","color","radius","time","trendline","builtDataset","convertQueries","convertUrls","console","warn","serializeQueryParams","str","param","val","encodeURIComponent","queryString","getJson","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","outStatistics","count","orderByFields","statisticType","onStatisticField","outStatisticFieldName","sort","token","utils","specUtils","requestUtils","baseUrl","src","cdnProtocol","cdnUrl","window","document","currentScript","substr","lastIndexOf","location","protocol","Cedar","options","version","spec","opts","chartTypes","width","undefined","height","autolabels","maxLabelLength","_events","_definition","_view","_tooltip","_transform","_methodQueue","_timeout","_pendingXhr","definition","this$1","_purgeMethodQueue","override","_chartType","type","_getSpecificationUrl","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","_convertDatasetsToDataset"],"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..52ae782c --- /dev/null +++ b/dist/charts/pie.json @@ -0,0 +1,80 @@ +{ + "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.{label.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": {"scale": "color", "field": "attributes.{label.field}"}, + "fillOpacity": {"value": 1} + }, + "hover": { + "fillOpacity": {"value": 0.8} + } + } + }, + { + "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