diff --git a/source/Ox.Geo/Ox.Geo.js b/source/Ox.Geo/Ox.Geo.js index 081edd4a..e1930d8a 100644 --- a/source/Ox.Geo/Ox.Geo.js +++ b/source/Ox.Geo/Ox.Geo.js @@ -76,7 +76,7 @@ Ox.load.Geo = function(options, callback) { @*/ Ox.COUNTRIES = data; - var colors = { + Ox.GEO_COLORS = { 'North America': [0, 0, 255], 'Northern America': [0, 0, 255], @@ -217,7 +217,7 @@ Ox.load.Geo = function(options, callback) { }; Ox.getGeoColor = function(str) { - return colors[str] || [128, 128, 128]; + return Ox.GEO_COLORS[str] || [128, 128, 128]; }; callback(true); diff --git a/source/Ox.UI/js/List/Ox.Chart.js b/source/Ox.UI/js/List/Ox.Chart.js index 7b202654..603e39eb 100644 --- a/source/Ox.UI/js/List/Ox.Chart.js +++ b/source/Ox.UI/js/List/Ox.Chart.js @@ -1,5 +1,24 @@ 'use strict'; +/*@ +Ox.Chart Bar Chart + () -> Chart object + (options) -> Chart object + (options, self) -> Chart object + options Options + color <[n]|[[n]]|[128, 128, 128]> Bar color + data {k: v, ...} or {k: {k: v, ...}, ...} + formatKey Format function for keys + keyAlign Alignment of keys + keyWidth Width of keys + rows undocumented + sort Sort + title Chart title + width Chart width + self shared private variable + +@*/ + Ox.Chart = function(options, self) { self = self || {}; @@ -12,6 +31,7 @@ Ox.Chart = function(options, self) { keyWidth: 128, rows: 1, sort: {key: 'value', operator: '-'}, + sortKey: null, title: '', width: 512 }) @@ -23,33 +43,76 @@ Ox.Chart = function(options, self) { overflowY: 'hidden' }); + self.valueWidth = self.options.width - self.options.keyWidth; + + self.keys = Object.keys(self.options.data); + if (Ox.isObject(self.options.data[self.keys[0]])) { + if (Ox.isUndefined(options.color)) { + self.options.color = [ + [192, 64, 64], [ 64, 192, 64], [ 64, 64, 192], + [192, 192, 64], [ 64, 192, 192], [192, 64, 192], + [192, 128, 64], [ 64, 192, 128], [128, 64, 192], + [192, 64, 128], [128, 192, 64], [ 64, 128, 192] + ]; + } + self.subData = {}; + } + self.sort = {}; + self.totals = {}; Ox.forEach(self.options.data, function(value, key) { + self.totals[key] = self.subData ? Ox.sum(value) : value; + if (self.subData) { + Object.keys(value).forEach(function(subKey) { + self.subData[subKey] = (self.subData[subKey] || 0) + value[subKey]; + }); + } self.sort[key] = key.replace(/(\d+)/g, function(number) { return Ox.pad(number, 16); }); }); + self.max = Ox.max(self.totals); + self.sum = Ox.sum(self.totals); + + if (self.subData) { + Ox.forEach(self.subData, function(subValue, subKey) { + self.sort[subKey] = subKey.replace(/(\d+)/g, function(number) { + return Ox.pad(number, 16); + }); + }); + self.subKeys = Object.keys(self.subData).sort(function(a, b) { + var aValue = self.subData[a], + bValue = self.subData[b]; + return a == '' ? 1 + : b == '' ? -1 + //: aValue < bValue ? 1 + //: aValue > bValue ? -1 + : self.sort[a] < self.sort[b] ? -1 + : self.sort[a] > self.sort[b] ? 1 + : 0; + }); + } - self.keys = Object.keys(self.options.data); self.items = self.keys.map(function(key) { return {key: key, value: self.options.data[key]}; }) .sort(function(a, b) { var key = self.options.sort.key, - aValue = key == 'key' ? self.sort[a.key] : a.value, - bValue = key == 'key' ? self.sort[b.key] : b.value; + aValue = key == 'key' ? self.sort[a.key] + : self.subData ? self.totals[a.key] : a.value, + bValue = key == 'key' ? self.sort[b.key] + : self.subData ? self.totals[b.key] : b.value; return aValue < bValue ? (self.options.sort.operator == '+' ? -1 : 1) : aValue > bValue ? (self.options.sort.operator == '+' ? 1 : -1) - : self.sort[a.key] < self.sort[b.key] ? -1 - : self.sort[a.key] > self.sort[b.key] ? 1 + : key == 'value' && self.sort[a.key] < self.sort[b.key] ? -1 + : key == 'value' && self.sort[a.key] > self.sort[b.key] ? 1 : 0; }); - self.values = self.items.map(function(item) { - return item.value; - }); - self.max = Ox.max(self.values); - self.sum = Ox.sum(self.values); - self.valueWidth = self.options.width - self.options.keyWidth; + + if (self.options.rows == 2) { + self.row = 0; + } + self.$title = Ox.Bar({size: 16}) .append( $('
') @@ -57,6 +120,7 @@ Ox.Chart = function(options, self) { .html(self.options.title) ) .appendTo(that); + self.$chart = $('
') .css({position: 'absolute', top: '16px'}) .append(renderChart()) @@ -80,6 +144,24 @@ Ox.Chart = function(options, self) { ]; } + function getWidths(values) { + var max, maxKeys, + total = Ox.sum(values), + totalWidth = Math.round(total / self.max * self.valueWidth), + widths = {}; + Ox.forEach(values, function(value, key) { + widths[key] = Math.round(value / total * totalWidth); + }); + while (Ox.sum(widths) != totalWidth) { + max = Ox.max(widths); + maxKeys = Ox.map(Object.keys(widths), function(key) { + return widths[key] == max ? key : null; + }); + widths[maxKeys[0]] += Ox.sum(widths) < totalWidth ? 1 : -1; + } + return widths; + } + function renderChart() { return Ox.TextList({ columns: getColumns(), @@ -99,30 +181,88 @@ Ox.Chart = function(options, self) { } function renderValue(value, data) { - var color = Ox.isFunction(self.options.color) - ? self.options.color(data.key) - : self.options.color, - $element = Ox.Element({ - element: '
', - tooltip: Ox.formatNumber(value) - + ' (' + Ox.formatPercent(value * self.options.rows, self.sum, 2) + ')' - }) - .css({ - width: Math.round(value / self.max * self.valueWidth) + 'px', - height: '14px', - borderRadius: '4px', - marginLeft: '-4px', + var $bars = [], + $element, + colors = [], len, widths; + if (!self.subData) { + $element = $bars[0] = Ox.Element({ + element: '
', + tooltip: Ox.formatNumber(value) + + ' (' + Ox.formatPercent(value * self.options.rows, self.sum, 2) + ')' + }) + .css({ + width: Math.round(value / self.max * self.valueWidth) + 'px', + height: '14px', + borderRadius: '4px', + marginLeft: '-4px' + }); + colors[0] = Ox.isFunction(self.options.color) + ? self.options.color(data.key) : self.options.color; + } else { + $element = $('
') + .css({ + width: Math.round(self.totals[data.key] / self.max * self.valueWidth) + 'px', + height: '14px', + marginLeft: '-4px' + }); + len = Ox.len(value); + widths = getWidths(value); + self.subKeys.forEach(function(subKey, subKeyIndex) { + var i = $bars.length, + subValue = value[subKey]; + if (subValue) { + $bars[i] = Ox.Element({ + element: '
', + /* + tooltip: Ox.formatNumber(self.totals[data.key]) + + ' (' + Ox.formatPercent(self.totals[data.key] * self.options.rows, self.sum, 2) + ')' + + '
' + subKey + ': ' + Ox.formatNumber(subValue) + + ' (' + Ox.formatPercent(subValue, self.totals[data.key], 2) + ')' + */ + tooltip: Ox.formatNumber(self.totals[data.key]) + + ' (' + Ox.formatPercent(self.totals[data.key] * self.options.rows, self.sum, 2) + ')' + }) + .css({ + float: 'left', + width: widths[subKey] + 'px', + height: '14px', + borderTopLeftRadius: i == 0 ? '4px' : 0, + borderBottomLeftRadius: i == 0 ? '4px' : 0, + borderTopRightRadius: i == len - 1 ? '4px' : 0, + borderBottomRightRadius: i == len - 1 ? '4px' : 0 + }) + .appendTo($element); + colors[i] = subKey == '' ? [128, 128, 128] + : Ox.isArray(self.options.color) + ? self.options.color[subKeyIndex % self.options.color.length] + : Ox.isObject(self.options.color) + ? self.options.color[subKey] + : self.options.color(subKey); + } }); - ['moz', 'o', 'webkit'].forEach(function(browser) { - $element.css({ - backgroundImage: '-' + browser - + '-linear-gradient(top, rgb(' + color.map(function(v) { - return Ox.limit(v + 16, 0, 255); - }).join(', ') + '), rgb(' + color.map(function(v) { - return Ox.limit(v - 16, 0, 255); - }) + '))' + } + $bars.forEach(function($bar, i) { + /* + if (self.options.rows == 2) { + colors[i] = colors[i].map(function(v) { + return v + (self.row % 2 == 0 ? 16 : -16); + }); + } + */ + ['moz', 'o', 'webkit'].forEach(function(browser) { + $bar.css({ + backgroundImage: '-' + browser + + '-linear-gradient(top, rgb(' + colors[i].map(function(v) { + return Ox.limit(v + 16, 0, 255); + }).join(', ') + '), rgb(' + colors[i].map(function(v) { + return Ox.limit(v - 16, 0, 255); + }) + '))' + }); }); }); + if (self.options.rows == 2) { + self.row++; + } return $element; } diff --git a/source/Ox.UI/js/Video/Ox.VideoEditor.js b/source/Ox.UI/js/Video/Ox.VideoEditor.js index 44429ada..fadaf958 100644 --- a/source/Ox.UI/js/Video/Ox.VideoEditor.js +++ b/source/Ox.UI/js/Video/Ox.VideoEditor.js @@ -4,9 +4,9 @@ /*@ Ox.VideoEditor VideoEditor Object - () -> VideoEditor Object - (options) -> VideoEditor Object - (options, self) -> VideoEditor Object + () -> VideoEditor Object + (options) -> VideoEditor Object + (options, self) -> VideoEditor Object options Options object self shared private variable @*/ diff --git a/source/Ox.UI/js/Video/Ox.VideoPlayer.js b/source/Ox.UI/js/Video/Ox.VideoPlayer.js index 45b3f687..6e6299d0 100644 --- a/source/Ox.UI/js/Video/Ox.VideoPlayer.js +++ b/source/Ox.UI/js/Video/Ox.VideoPlayer.js @@ -72,6 +72,7 @@ Ox.VideoPlayer Generic Video Player ({resolution: url, ...} or {resolution: [part1, part2, ...], ...}) volume Volume (0-1) width Width in px + self shared private variable @*/ Ox.VideoPlayer = function(options, self) {