diff --git a/README.md b/README.md index 3cb2cc8..4040d48 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ without the workload of running a server, installing and maintaining software an the professional concepts of GIS. ## Status -* The first version of the library was released on the 31st of March 2016 +* The first (1.0) version of the library was released on the 31st of March 2016 +* The seconc (2.0) version of the library was released on the 20th of March 2017 * The library is under still under active development and we advise users to check out the develop branch for the latest features * New releases with incremental functionality are frequent at this stage diff --git a/dist/s4a.js b/dist/s4a.js index ecf06f4..6edcead 100644 --- a/dist/s4a.js +++ b/dist/s4a.js @@ -1,6 +1,6 @@ -/*! s4a - v1.0.0 - 2016-06-21 +/*! s4a - v1.0.0 - 2017-04-03 * https://github.com/SDI4Apps/s4a.js -* Copyright (c) 2016 SDI4Apps Partnership; Licensed */ +* Copyright (c) 2017 SDI4Apps Partnership; Licensed */ 'use strict'; /** @@ -295,6 +295,11 @@ s4a.analytics.Routing = (function() { s4a.extend('data'); +/** + * SensLog communication object + * + * @class + */ s4a.data.SensLog = (function() { /** * Class with methods to interact with SensLog @@ -1507,50 +1512,6 @@ s4a.map.VizLayer = function() { }; -'use strict'; - -s4a.extend('mobile'); - -s4a.mobile.FeatureSync = (function() { - - /** - * [module description] - * @exports s4a.mobile.FeatureSync - */ - var module = {}; - - /** - * Check out a portion of a feature layer - */ - module.CheckOut = function() { - - }; - - /** - * Check in an edited feature layer - */ - module.CheckIn = function() { - - }; - - /** - * Get conflicts if any for a featyre layer - */ - module.GetConflicts = function() { - - }; - - /** - * Resolve conflict - */ - module.Resolve = function() { - - }; - - return module; - -}()); - /* global s4a, LocalFileSystem */ 'use strict'; @@ -1871,6 +1832,50 @@ s4a.mobile.OfflineTileLayer.clearBaseMapCache = function(baseMapId) { }; +'use strict'; + +s4a.extend('mobile'); + +s4a.mobile.FeatureSync = (function() { + + /** + * [module description] + * @exports s4a.mobile.FeatureSync + */ + var module = {}; + + /** + * Check out a portion of a feature layer + */ + module.CheckOut = function() { + + }; + + /** + * Check in an edited feature layer + */ + module.CheckIn = function() { + + }; + + /** + * Get conflicts if any for a featyre layer + */ + module.GetConflicts = function() { + + }; + + /** + * Resolve conflict + */ + module.Resolve = function() { + + }; + + return module; + +}()); + 'use strict'; s4a.extend('viz'); @@ -2531,76 +2536,337 @@ s4a.viz.Legend = function(chartConfig) { 'use strict'; /** - * Pie visualization - * - * @param {s4a.viz.ViewCoordinator} viewCoordinator - * @param {s4a.viz.ChartConfig} mChartConfig - * @constructor + * Enumeration of size-scales + * @readonly + * @enum {number} */ -s4a.viz.Pie = function(viewCoordinator, mChartConfig) { - var chartData, currentData, currentScale, scale, arc, bigArc; - var _self = this; - var transitionTime = 400; - +s4a.viz.Sizes = { /** - * Internal reference to Pie svg element. - * Use getSvg to retrieve it - * - * @private + * From 5px to 19px + * @type Array */ - var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg')); - - function changeCollapsedState(collapsed) { - currentScale = collapsed ? scale : 1; - - var featureWidth = mChartConfig.width * currentScale; - var featureHeight = mChartConfig.height * currentScale; - var g = svg.selectAll('g'); - - if (currentScale === 1) { - svg.attr('width', featureWidth) - .attr('height',featureHeight); - - $(_self).trigger('resize'); + 'small': ['5', '7', '9', '11', '13', '15', '17', '19'], + /** + * From 10px to 50px + * @type Array + */ + 'medium': ['10', '15', '25', '30', '35', '40', '45', '50'], + /** + * From 10px to 80px + * @type Array + */ + 'large': ['10', '20', '30', '40', '50', '60', '70', '80'] +}; - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); +/** + * Enumeration for font sizes + * @readonly + * @enum {number} + */ +s4a.viz.FontSizes = { + /** + * Small font size + * @type Number + */ + 'small': 10, + /** + * The default font size + * @type Number + */ + 'normal': 12, + /** + * A bigger font-size + * @type Number + */ + 'medium': 14, + /** + * Large font-size + * @type Number + */ + 'large': 18 +}; - svg.selectAll('path') - .transition() - .duration(transitionTime) - .attr('d', currentScale === 1 ? bigArc : arc); - } else { - svg.selectAll('path') - .transition() - .duration(transitionTime) - .attr('d', currentScale === 1 ? bigArc : arc); +'use strict'; +/* global s4a */ - setTimeout(function() { - svg.attr('width', featureWidth) - .attr('height',featureHeight); +/** + * A top level object that coordinates data and visualizations + * + * @param {Object} pData + * @constructor + * @returns {s4a.viz.ViewCoordinator} + */ +s4a.viz.ViewCoordinator = function(pData) { - $(_self).trigger('resize'); + var _data = pData; + var _listeners = []; + var _self = {}; - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + /** + * Subscribes an object to publish events from the ViewCoordinator + * + * @returns {s4a.viz.ViewCoordinator} + */ + _self.publish = function() { + for (var i = 0; i < _listeners.length; i++) { + var listener = _listeners[i]; + if (listener.update) { + listener.update(_data); + console.info('Published ' + i); + } else { + console.debug('Subscribed object ' + i + ' does not implement the update interface', + listener); + } + } + return _self; + }; - }, transitionTime); + /** + * Update the data object + * + * @param {Object} pData + * @returns {s4a.viz.ViewCoordinator} + */ + _self.setData = function(pData) { + _data = pData; + _self.publish(); + return _self; + }; + /** + * Subscribe an object to the ViewCoordinator + * + * @param {Object} pObj + * @returns {s4a.viz.ViewCoordinator} + */ + _self.subscribe = function(pObj) { + if (_listeners.indexOf(pObj) < 0) { + _listeners.push(pObj); } - } + return _self; + }; /** - * Create new pie chart + * Unsubscribe an object from the ViewCoordinator * - * @param {integer} width optional width of svg - * @param {integer} height optional height of svg - * @private + * @param {Object} pObj + * @returns {s4a.viz.ViewCoordinator} */ - function updateChart(width, height) { - // pick the first series - currentData = chartData.series[0].values; + _self.unsubscribe = function(pObj) { + var _modListeners = []; + for (var i = 0; i < _listeners.length; i++) { + if (_listeners[i] !== pObj) { + _modListeners.push(_listeners[i]); + } + } + _listeners = _modListeners; + return _self; + }; - // and the first color - var colors = s4a.viz.color[mChartConfig.colors[0]][currentData.length]; + _self.applyFilter = function() { + _self.publish(); + return _self; + }; + + return _self; + +}; + +'use strict'; +/* global s4a */ + +/** + *

This is an abstract top-level object that coordinates data and visualizations + * that take part in a coordinated view

+ * + *

Any visualization object must implement an interface that contains the methods + * update and filter

+ * + *

The object receives as part of the constructor a ViewCoordinator object + * that implicitly contains data

+ * + *

The object receives as part of the constructor a DOMElement identified by its + * ID, typically i DIV in which it is to be drawn

+ * + * @abstract + * @constructor + * @param {s4a.viz.ViewCoordinator} viewCoordinator + * @param {DOMElement} domElement + * @returns {s4a.viz.VizObj} + */ +s4a.viz.VizObj = function(viewCoordinator, domElement) { + var _self = this; + + viewCoordinator.subscribe(_self); + + /** + * Update the visualization + * + * @abstract + */ + _self.update = function() { + throw new Error('Must be implemented by sub-class'); + }; + + /** + * Apply a filter to the visualization + * + * @abstract + */ + _self.filter = function(filter) { + throw new Error('Must be implemented by sub-class'); + }; + + _self.get = function() { + throw new Error('Must be implemented by sub-class'); + }; +}; + +'use strict'; +/* global s4a */ + +/** + * Enumeration + * + * @enum {number} + * @readonly + */ +s4a.viz.VizType = { + /** + * Chart + */ + CHART: 1, + + /** + * Map + */ + MAP: 2 +}; + +'use strict'; +s4a.extend('viz.chart'); + +/** + * Create a new Bar chart object + * + * @class + * @classdesc + * Bar chart object + */ +s4a.viz.chart.Bar = function() { + +}; + +'use strict'; +/** + * Create a new bubble chart object + * + * @class + * @classdesc + * Stacked bubble chart object + */ +s4a.viz.chart.Bubble = function() { + +}; + +'use strict'; +/** + * Create a new row chart object + * + * @class + * @classdesc + * Row chart object + */ +s4a.viz.chart.Row = function() { + +}; + +'use strict'; +s4a.extend('viz.chart'); + +/** + * Create a new line chart object + * + * @class + * @classdesc + * Bar line chart object + */ +s4a.viz.chart.Line = function() { + +}; + +'use strict'; +/** + * Pie visualization + * + * @param {s4a.viz.ViewCoordinator} viewCoordinator + * @param {s4a.viz.ChartConfig} mChartConfig + * @constructor + */ +s4a.viz.Pie = function(viewCoordinator, mChartConfig) { + var chartData, currentData, currentScale, scale, arc, bigArc; + var _self = this; + var transitionTime = 400; + + /** + * Internal reference to Pie svg element. + * Use getSvg to retrieve it + * + * @private + */ + var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg')); + + function changeCollapsedState(collapsed) { + currentScale = collapsed ? scale : 1; + + var featureWidth = mChartConfig.width * currentScale; + var featureHeight = mChartConfig.height * currentScale; + var g = svg.selectAll('g'); + + if (currentScale === 1) { + svg.attr('width', featureWidth) + .attr('height',featureHeight); + + $(_self).trigger('resize'); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + + svg.selectAll('path') + .transition() + .duration(transitionTime) + .attr('d', currentScale === 1 ? bigArc : arc); + } else { + svg.selectAll('path') + .transition() + .duration(transitionTime) + .attr('d', currentScale === 1 ? bigArc : arc); + + setTimeout(function() { + svg.attr('width', featureWidth) + .attr('height',featureHeight); + + $(_self).trigger('resize'); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + + }, transitionTime); + + } + } + + /** + * Create new pie chart + * + * @param {integer} width optional width of svg + * @param {integer} height optional height of svg + * @private + */ + function updateChart(width, height) { + // pick the first series + currentData = chartData.series[0].values; + + // and the first color + var colors = s4a.viz.color[mChartConfig.colors[0]][currentData.length]; mChartConfig.height = mChartConfig.height || mChartConfig.width; mChartConfig.collapsedHeight = mChartConfig.collapsedHeight || mChartConfig.collapsedWidth; @@ -2739,260 +3005,51 @@ s4a.viz.Pie = function(viewCoordinator, mChartConfig) { 'use strict'; /** - * Enumeration of size-scales - * @readonly - * @enum {number} - */ -s4a.viz.Sizes = { - /** - * From 5px to 19px - * @type Array - */ - 'small': ['5', '7', '9', '11', '13', '15', '17', '19'], - /** - * From 10px to 50px - * @type Array - */ - 'medium': ['10', '15', '25', '30', '35', '40', '45', '50'], - /** - * From 10px to 80px - * @type Array - */ - 'large': ['10', '20', '30', '40', '50', '60', '70', '80'] -}; - -/** - * Enumeration for font sizes - * @readonly - * @enum {number} - */ -s4a.viz.FontSizes = { - /** - * Small font size - * @type Number - */ - 'small': 10, - /** - * The default font size - * @type Number - */ - 'normal': 12, - /** - * A bigger font-size - * @type Number - */ - 'medium': 14, - /** - * Large font-size - * @type Number - */ - 'large': 18 -}; - -'use strict'; -/* global s4a */ - -/** - * A top level object that coordinates data and visualizations - * - * @param {Object} pData - * @constructor - * @returns {s4a.viz.ViewCoordinator} - */ -s4a.viz.ViewCoordinator = function(pData) { - - var _data = pData; - var _listeners = []; - var _self = {}; - - /** - * Subscribes an object to publish events from the ViewCoordinator - * - * @returns {s4a.viz.ViewCoordinator} - */ - _self.publish = function() { - for (var i = 0; i < _listeners.length; i++) { - var listener = _listeners[i]; - if (listener.update) { - listener.update(_data); - console.info('Published ' + i); - } else { - console.debug('Subscribed object ' + i + ' does not implement the update interface', - listener); - } - } - return _self; - }; - - /** - * Update the data object - * - * @param {Object} pData - * @returns {s4a.viz.ViewCoordinator} - */ - _self.setData = function(pData) { - _data = pData; - _self.publish(); - return _self; - }; - - /** - * Subscribe an object to the ViewCoordinator - * - * @param {Object} pObj - * @returns {s4a.viz.ViewCoordinator} - */ - _self.subscribe = function(pObj) { - if (_listeners.indexOf(pObj) < 0) { - _listeners.push(pObj); - } - return _self; - }; - - /** - * Unsubscribe an object from the ViewCoordinator - * - * @param {Object} pObj - * @returns {s4a.viz.ViewCoordinator} - */ - _self.unsubscribe = function(pObj) { - var _modListeners = []; - for (var i = 0; i < _listeners.length; i++) { - if (_listeners[i] !== pObj) { - _modListeners.push(_listeners[i]); - } - } - _listeners = _modListeners; - return _self; - }; - - _self.applyFilter = function() { - _self.publish(); - return _self; - }; - - return _self; - -}; - -'use strict'; -/* global s4a */ - -/** - *

This is an abstract top-level object that coordinates data and visualizations - * that take part in a coordinated view

- * - *

Any visualization object must implement an interface that contains the methods - * update and filter

- * - *

The object receives as part of the constructor a ViewCoordinator object - * that implicitly contains data

- * - *

The object receives as part of the constructor a DOMElement identified by its - * ID, typically i DIV in which it is to be drawn

- * - * @abstract - * @constructor - * @param {s4a.viz.ViewCoordinator} viewCoordinator - * @param {DOMElement} domElement - * @returns {s4a.viz.VizObj} - */ -s4a.viz.VizObj = function(viewCoordinator, domElement) { - var _self = this; - - viewCoordinator.subscribe(_self); - - /** - * Update the visualization - * - * @abstract - */ - _self.update = function() { - throw new Error('Must be implemented by sub-class'); - }; - - /** - * Apply a filter to the visualization - * - * @abstract - */ - _self.filter = function(filter) { - throw new Error('Must be implemented by sub-class'); - }; - - _self.get = function() { - throw new Error('Must be implemented by sub-class'); - }; -}; - -'use strict'; -/* global s4a */ - -/** - * Enumeration - * - * @enum {number} - * @readonly - */ -s4a.viz.VizType = { - /** - * Chart - */ - CHART: 1, - - /** - * Map - */ - MAP: 2 -}; - -'use strict'; -s4a.extend('viz.chart'); - -/** - * Create a new Bar chart object + * Create a new Row chart object * * @class * @classdesc - * Bar chart object + * Row chart object */ -s4a.viz.chart.Bar = function() { +s4a.viz.chart.Row = function() { }; 'use strict'; /** - * Create a new Pie chart object + * Create a new Scatter chart object * * @class * @classdesc - * Pie chart object + * Scatter chart object */ -s4a.viz.chart.Pie = function() { +s4a.viz.chart.Scatter = function() { }; 'use strict'; +s4a.extend('viz.chart'); + /** - * Create a new Row chart object + * Create a new stacked line chart object * * @class * @classdesc - * Row chart object + * Stacked line chart object */ -s4a.viz.chart.Row = function() { +s4a.viz.chart.StackedLine = function() { }; 'use strict'; /** - * Create a new Scatter chart object + * Create a new stacked row chart object * * @class * @classdesc - * Scatter chart object + * Stacked row chart object */ -s4a.viz.chart.Scatter = function() { +s4a.viz.chart.StackedRow = function() { }; @@ -3426,6 +3483,20 @@ s4a.viz.map.getMap = function(pDomNode, pChartData) { }); }; +'use strict'; +s4a.extend('viz.map'); + +/** + * Create a new Prism chart object + * + * @class + * @classdesc + * Prism chart object + */ +s4a.viz.map.Prism = function() { + +}; + 'use strict'; /** * Define namespace utilities diff --git a/src/data/SensLog.js b/src/data/SensLog.js index 6987223..b1babe4 100644 --- a/src/data/SensLog.js +++ b/src/data/SensLog.js @@ -2,6 +2,11 @@ s4a.extend('data'); +/** + * SensLog communication object + * + * @class + */ s4a.data.SensLog = (function() { /** * Class with methods to interact with SensLog diff --git a/src/ir/ir.jsdoc b/src/ir/ir.jsdoc index 6a28a91..0c29496 100644 --- a/src/ir/ir.jsdoc +++ b/src/ir/ir.jsdoc @@ -1,4 +1,5 @@ /** * Information retrieval related methods + * * @namespace s4a.ir */ diff --git a/src/viz/Pie.js b/src/viz/Pie.js deleted file mode 100644 index 8fee5cb..0000000 --- a/src/viz/Pie.js +++ /dev/null @@ -1,207 +0,0 @@ -'use strict'; -/** - * Pie visualization - * - * @param {s4a.viz.ViewCoordinator} viewCoordinator - * @param {s4a.viz.ChartConfig} mChartConfig - * @constructor - */ -s4a.viz.Pie = function(viewCoordinator, mChartConfig) { - var chartData, currentData, currentScale, scale, arc, bigArc; - var _self = this; - var transitionTime = 400; - - /** - * Internal reference to Pie svg element. - * Use getSvg to retrieve it - * - * @private - */ - var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg')); - - function changeCollapsedState(collapsed) { - currentScale = collapsed ? scale : 1; - - var featureWidth = mChartConfig.width * currentScale; - var featureHeight = mChartConfig.height * currentScale; - var g = svg.selectAll('g'); - - if (currentScale === 1) { - svg.attr('width', featureWidth) - .attr('height',featureHeight); - - $(_self).trigger('resize'); - - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); - - svg.selectAll('path') - .transition() - .duration(transitionTime) - .attr('d', currentScale === 1 ? bigArc : arc); - } else { - svg.selectAll('path') - .transition() - .duration(transitionTime) - .attr('d', currentScale === 1 ? bigArc : arc); - - setTimeout(function() { - svg.attr('width', featureWidth) - .attr('height',featureHeight); - - $(_self).trigger('resize'); - - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); - - }, transitionTime); - - } - } - - /** - * Create new pie chart - * - * @param {integer} width optional width of svg - * @param {integer} height optional height of svg - * @private - */ - function updateChart(width, height) { - // pick the first series - currentData = chartData.series[0].values; - - // and the first color - var colors = s4a.viz.color[mChartConfig.colors[0]][currentData.length]; - - mChartConfig.height = mChartConfig.height || mChartConfig.width; - mChartConfig.collapsedHeight = mChartConfig.collapsedHeight || mChartConfig.collapsedWidth; - - scale = mChartConfig.collapsed ? mChartConfig.collapsedWidth / mChartConfig.width : 1; - - currentScale = scale; - - var radius = Math.min(mChartConfig.width, mChartConfig.height) / 2; - var collapsedRadius = Math.min(mChartConfig.collapsedWidth, mChartConfig.collapsedHeight) / 2; - - var color = d3.scale.ordinal() - .range(colors); - - arc = d3.svg.arc() - .outerRadius(collapsedRadius); - - bigArc = d3.svg.arc() - .outerRadius(radius); - - if (mChartConfig.innerWidth) { - bigArc.innerRadius(radius - mChartConfig.innerWidth); - } - - var pie = d3.layout.pie() - .sort(null) - .value(function(d) { - return d.valx; - }); - - // delete all current objects - if (svg) { - svg.selectAll('*').remove(); - } - - var g = svg.selectAll('.arc') - .data(pie(currentData)) - .enter() - .append('g') - .attr('class', 'arc'); - - // avoid flash - g.attr('transform', 'translate(' + -4000 + ',' + -4000 + ')'); - - g.append('path') - .attr('d', mChartConfig.collapsed ? arc : bigArc) - .style('fill', function(d) { - return color(d.data.label); - }); - - if (mChartConfig.collapsed) { - changeCollapsedState(true); - } - - if (mChartConfig.collapsible) { - g.on('click', function() { - changeCollapsedState(currentScale === 1); - }); - } - } - - /** - * Get the geometry bound to the vizObject - * - * @returns {Object} set of lonlat or null - */ - _self.getGeometry = function() { - return chartData.geometry; - }; - - /** - * Get the svg representation of the vizObject - * - * @returns {d3.svg} set of lonlat or null - */ - _self.getSvg = function() { - return svg; - }; - - /** - * Set the visibility of the pie visualization (`true` or `false`). - * - * @param {boolean} visible The visibility of the layer. - */ - _self.setVisible = function(visible) { - if (svg) { - svg.attr('display', visible ? null : 'none'); - } - }; - - /** - * Redraw the vizObject - */ - _self.redraw = function() { - var g = svg.selectAll('g'); - var featureWidth = mChartConfig.width * currentScale; - var featureHeight = mChartConfig.height * currentScale; - - svg.attr('width', featureWidth) - .attr('height', featureHeight); - - g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); - }; - - // Methods inherited from top level vizObj - - /** - * Callback from ViewCoordinator. - * Update data object for the visualization - * - * @param {Object} mChartData - */ - _self.update = function(mChartData) { - chartData = mChartData; - updateChart(); - _self.redraw(); - }; - - /** - * Apply a filter to the visualization - * - * @abstract - */ - _self.filter = function() { - throw new Error('Must be implemented by sub-class'); - }; - - _self.get = function() { - throw new Error('Must be implemented by sub-class'); - }; - - viewCoordinator.subscribe(_self); - - return _self; -}; diff --git a/src/viz/chart/Bubble.js b/src/viz/chart/Bubble.js new file mode 100644 index 0000000..e2fb4e9 --- /dev/null +++ b/src/viz/chart/Bubble.js @@ -0,0 +1,11 @@ +'use strict'; +/** + * Create a new bubble chart object + * + * @class + * @classdesc + * Stacked bubble chart object + */ +s4a.viz.chart.Bubble = function() { + +}; diff --git a/src/viz/chart/GroupedBar.js b/src/viz/chart/GroupedBar.js new file mode 100644 index 0000000..9e63815 --- /dev/null +++ b/src/viz/chart/GroupedBar.js @@ -0,0 +1,11 @@ +'use strict'; +/** + * Create a new row chart object + * + * @class + * @classdesc + * Row chart object + */ +s4a.viz.chart.Row = function() { + +}; diff --git a/src/viz/chart/Line.js b/src/viz/chart/Line.js new file mode 100644 index 0000000..3879b64 --- /dev/null +++ b/src/viz/chart/Line.js @@ -0,0 +1,13 @@ +'use strict'; +s4a.extend('viz.chart'); + +/** + * Create a new line chart object + * + * @class + * @classdesc + * Bar line chart object + */ +s4a.viz.chart.Line = function() { + +}; diff --git a/src/viz/chart/Pie.js b/src/viz/chart/Pie.js index 6fc96da..8fee5cb 100644 --- a/src/viz/chart/Pie.js +++ b/src/viz/chart/Pie.js @@ -1,11 +1,207 @@ -'use strict'; -/** - * Create a new Pie chart object - * - * @class - * @classdesc - * Pie chart object - */ -s4a.viz.chart.Pie = function() { - -}; +'use strict'; +/** + * Pie visualization + * + * @param {s4a.viz.ViewCoordinator} viewCoordinator + * @param {s4a.viz.ChartConfig} mChartConfig + * @constructor + */ +s4a.viz.Pie = function(viewCoordinator, mChartConfig) { + var chartData, currentData, currentScale, scale, arc, bigArc; + var _self = this; + var transitionTime = 400; + + /** + * Internal reference to Pie svg element. + * Use getSvg to retrieve it + * + * @private + */ + var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg')); + + function changeCollapsedState(collapsed) { + currentScale = collapsed ? scale : 1; + + var featureWidth = mChartConfig.width * currentScale; + var featureHeight = mChartConfig.height * currentScale; + var g = svg.selectAll('g'); + + if (currentScale === 1) { + svg.attr('width', featureWidth) + .attr('height',featureHeight); + + $(_self).trigger('resize'); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + + svg.selectAll('path') + .transition() + .duration(transitionTime) + .attr('d', currentScale === 1 ? bigArc : arc); + } else { + svg.selectAll('path') + .transition() + .duration(transitionTime) + .attr('d', currentScale === 1 ? bigArc : arc); + + setTimeout(function() { + svg.attr('width', featureWidth) + .attr('height',featureHeight); + + $(_self).trigger('resize'); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + + }, transitionTime); + + } + } + + /** + * Create new pie chart + * + * @param {integer} width optional width of svg + * @param {integer} height optional height of svg + * @private + */ + function updateChart(width, height) { + // pick the first series + currentData = chartData.series[0].values; + + // and the first color + var colors = s4a.viz.color[mChartConfig.colors[0]][currentData.length]; + + mChartConfig.height = mChartConfig.height || mChartConfig.width; + mChartConfig.collapsedHeight = mChartConfig.collapsedHeight || mChartConfig.collapsedWidth; + + scale = mChartConfig.collapsed ? mChartConfig.collapsedWidth / mChartConfig.width : 1; + + currentScale = scale; + + var radius = Math.min(mChartConfig.width, mChartConfig.height) / 2; + var collapsedRadius = Math.min(mChartConfig.collapsedWidth, mChartConfig.collapsedHeight) / 2; + + var color = d3.scale.ordinal() + .range(colors); + + arc = d3.svg.arc() + .outerRadius(collapsedRadius); + + bigArc = d3.svg.arc() + .outerRadius(radius); + + if (mChartConfig.innerWidth) { + bigArc.innerRadius(radius - mChartConfig.innerWidth); + } + + var pie = d3.layout.pie() + .sort(null) + .value(function(d) { + return d.valx; + }); + + // delete all current objects + if (svg) { + svg.selectAll('*').remove(); + } + + var g = svg.selectAll('.arc') + .data(pie(currentData)) + .enter() + .append('g') + .attr('class', 'arc'); + + // avoid flash + g.attr('transform', 'translate(' + -4000 + ',' + -4000 + ')'); + + g.append('path') + .attr('d', mChartConfig.collapsed ? arc : bigArc) + .style('fill', function(d) { + return color(d.data.label); + }); + + if (mChartConfig.collapsed) { + changeCollapsedState(true); + } + + if (mChartConfig.collapsible) { + g.on('click', function() { + changeCollapsedState(currentScale === 1); + }); + } + } + + /** + * Get the geometry bound to the vizObject + * + * @returns {Object} set of lonlat or null + */ + _self.getGeometry = function() { + return chartData.geometry; + }; + + /** + * Get the svg representation of the vizObject + * + * @returns {d3.svg} set of lonlat or null + */ + _self.getSvg = function() { + return svg; + }; + + /** + * Set the visibility of the pie visualization (`true` or `false`). + * + * @param {boolean} visible The visibility of the layer. + */ + _self.setVisible = function(visible) { + if (svg) { + svg.attr('display', visible ? null : 'none'); + } + }; + + /** + * Redraw the vizObject + */ + _self.redraw = function() { + var g = svg.selectAll('g'); + var featureWidth = mChartConfig.width * currentScale; + var featureHeight = mChartConfig.height * currentScale; + + svg.attr('width', featureWidth) + .attr('height', featureHeight); + + g.attr('transform', 'translate(' + featureWidth / 2 + ',' + featureHeight / 2 + ')'); + }; + + // Methods inherited from top level vizObj + + /** + * Callback from ViewCoordinator. + * Update data object for the visualization + * + * @param {Object} mChartData + */ + _self.update = function(mChartData) { + chartData = mChartData; + updateChart(); + _self.redraw(); + }; + + /** + * Apply a filter to the visualization + * + * @abstract + */ + _self.filter = function() { + throw new Error('Must be implemented by sub-class'); + }; + + _self.get = function() { + throw new Error('Must be implemented by sub-class'); + }; + + viewCoordinator.subscribe(_self); + + return _self; +}; diff --git a/src/viz/chart/StackedLine.js b/src/viz/chart/StackedLine.js new file mode 100644 index 0000000..227d7f6 --- /dev/null +++ b/src/viz/chart/StackedLine.js @@ -0,0 +1,13 @@ +'use strict'; +s4a.extend('viz.chart'); + +/** + * Create a new stacked line chart object + * + * @class + * @classdesc + * Stacked line chart object + */ +s4a.viz.chart.StackedLine = function() { + +}; diff --git a/src/viz/chart/StackedRow.js b/src/viz/chart/StackedRow.js new file mode 100644 index 0000000..0ba85f0 --- /dev/null +++ b/src/viz/chart/StackedRow.js @@ -0,0 +1,11 @@ +'use strict'; +/** + * Create a new stacked row chart object + * + * @class + * @classdesc + * Stacked row chart object + */ +s4a.viz.chart.StackedRow = function() { + +}; diff --git a/src/viz/map/Prism.js b/src/viz/map/Prism.js new file mode 100644 index 0000000..b4010ac --- /dev/null +++ b/src/viz/map/Prism.js @@ -0,0 +1,13 @@ +'use strict'; +s4a.extend('viz.map'); + +/** + * Create a new Prism chart object + * + * @class + * @classdesc + * Prism chart object + */ +s4a.viz.map.Prism = function() { + +};