diff --git a/custom/chart-tool-config.json b/custom/chart-tool-config.json index ff33b107..2ab57731 100644 --- a/custom/chart-tool-config.json +++ b/custom/chart-tool-config.json @@ -134,6 +134,12 @@ "thumbnailWidth": 460 }, + "slack": { + "enable_webhooks": false, + "username": "Chart tool", + "edit_address": "https://chart-tool-demo.herokuapp.com/chart/edit/" + }, + "embedJS": "http://beta.images.theglobeandmail.com/static/templates/tools/chart-tool/1.2.0/chart-tool.min.js", "embedCSS": "http://beta.images.theglobeandmail.com/static/templates/tools/chart-tool/1.2.0/chart-tool.min.css" diff --git a/custom/meteor-config.js b/custom/meteor-config.js index 359b7144..2b4f75f4 100644 --- a/custom/meteor-config.js +++ b/custom/meteor-config.js @@ -10,6 +10,8 @@ app_settings = { s3: config.image, + slack: config.slack, + embedJS: config.embedJS, embedCSS: config.embedCSS, diff --git a/meteor/client/templates/chart-new/chart-new.js b/meteor/client/templates/chart-new/chart-new.js index 2da83038..6920b710 100644 --- a/meteor/client/templates/chart-new/chart-new.js +++ b/meteor/client/templates/chart-new/chart-new.js @@ -15,6 +15,7 @@ Template.chartNew.events({ console.log(err); } else { console.log("Chart added with id: " + result); + Meteor.call('postSlackMessage', slug, result); Session.set("chartId", result); Router.go('chart.edit', {_id: Session.get("chartId")}); } @@ -29,4 +30,4 @@ Template.chartNew.events({ } } -}); \ No newline at end of file +}); diff --git a/meteor/lib/chart-tool/scripts/chart-tool.js b/meteor/lib/chart-tool/scripts/chart-tool.js index bf73792f..0b053463 100644 --- a/meteor/lib/chart-tool/scripts/chart-tool.js +++ b/meteor/lib/chart-tool/scripts/chart-tool.js @@ -1006,71 +1006,50 @@ function ascendingComparator(f) { var ascendingBisect = bisector(ascending$1); var bisectRight = ascendingBisect.right; +function pair(a, b) { + return [a, b]; +} + var number = function(x) { return x === null ? NaN : +x; }; -var variance = function(array, f) { - var n = array.length, - m = 0, - a, - d, - s = 0, +var extent = function(values, valueof) { + var n = values.length, i = -1, - j = 0; - - if (f == null) { - while (++i < n) { - if (!isNaN(a = number(array[i]))) { - d = a - m; - m += d / ++j; - s += d * (a - m); + value, + min, + max; + + if (valueof == null) { + while (++i < n) { // Find the first comparable value. + if ((value = values[i]) != null && value >= value) { + min = max = value; + while (++i < n) { // Compare the remaining values. + if ((value = values[i]) != null) { + if (min > value) min = value; + if (max < value) max = value; + } + } } } } else { - while (++i < n) { - if (!isNaN(a = number(f(array[i], i, array)))) { - d = a - m; - m += d / ++j; - s += d * (a - m); + while (++i < n) { // Find the first comparable value. + if ((value = valueof(values[i], i, values)) != null && value >= value) { + min = max = value; + while (++i < n) { // Compare the remaining values. + if ((value = valueof(values[i], i, values)) != null) { + if (min > value) min = value; + if (max < value) max = value; + } + } } } } - if (j > 1) return s / (j - 1); -}; - -var deviation = function(array, f) { - var v = variance(array, f); - return v ? Math.sqrt(v) : v; -}; - -var extent = function(array, f) { - var i = -1, - n = array.length, - a, - b, - c; - - if (f == null) { - while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; } - while (++i < n) if ((b = array[i]) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } - - else { - while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = c = b; break; } - while (++i < n) if ((b = f(array[i], i, array)) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } - - return [a, c]; + return [min, max]; }; var array = Array.prototype; @@ -1107,14 +1086,42 @@ var e5 = Math.sqrt(10); var e2 = Math.sqrt(2); var ticks = function(start, stop, count) { - var step = tickStep(start, stop, count); - return range( - Math.ceil(start / step) * step, - Math.floor(stop / step) * step + step / 2, // inclusive - step - ); + var reverse = stop < start, + i = -1, + n, + ticks, + step; + + if (reverse) n = start, start = stop, stop = n; + + if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return []; + + if (step > 0) { + start = Math.ceil(start / step); + stop = Math.floor(stop / step); + ticks = new Array(n = Math.ceil(stop - start + 1)); + while (++i < n) ticks[i] = (start + i) * step; + } else { + start = Math.floor(start * step); + stop = Math.ceil(stop * step); + ticks = new Array(n = Math.ceil(start - stop + 1)); + while (++i < n) ticks[i] = (start - i) / step; + } + + if (reverse) ticks.reverse(); + + return ticks; }; +function tickIncrement(start, stop, count) { + var step = (stop - start) / Math.max(0, count), + power = Math.floor(Math.log(step) / Math.LN10), + error = step / Math.pow(10, power); + return power >= 0 + ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power) + : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1); +} + function tickStep(start, stop, count) { var step0 = Math.abs(stop - start) / Math.max(0, count), step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), @@ -1129,65 +1136,87 @@ var sturges = function(values) { return Math.ceil(Math.log(values.length) / Math.LN2) + 1; }; -var threshold = function(array, p, f) { - if (f == null) f = number; - if (!(n = array.length)) return; - if ((p = +p) <= 0 || n < 2) return +f(array[0], 0, array); - if (p >= 1) return +f(array[n - 1], n - 1, array); +var threshold = function(values, p, valueof) { + if (valueof == null) valueof = number; + if (!(n = values.length)) return; + if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values); + if (p >= 1) return +valueof(values[n - 1], n - 1, values); var n, - h = (n - 1) * p, - i = Math.floor(h), - a = +f(array[i], i, array), - b = +f(array[i + 1], i + 1, array); - return a + (b - a) * (h - i); + i = (n - 1) * p, + i0 = Math.floor(i), + value0 = +valueof(values[i0], i0, values), + value1 = +valueof(values[i0 + 1], i0 + 1, values); + return value0 + (value1 - value0) * (i - i0); }; -var max = function(array, f) { - var i = -1, - n = array.length, - a, - b; - - if (f == null) { - while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; } - while (++i < n) if ((b = array[i]) != null && b > a) a = b; +var max = function(values, valueof) { + var n = values.length, + i = -1, + value, + max; + + if (valueof == null) { + while (++i < n) { // Find the first comparable value. + if ((value = values[i]) != null && value >= value) { + max = value; + while (++i < n) { // Compare the remaining values. + if ((value = values[i]) != null && value > max) { + max = value; + } + } + } + } } else { - while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; } - while (++i < n) if ((b = f(array[i], i, array)) != null && b > a) a = b; + while (++i < n) { // Find the first comparable value. + if ((value = valueof(values[i], i, values)) != null && value >= value) { + max = value; + while (++i < n) { // Compare the remaining values. + if ((value = valueof(values[i], i, values)) != null && value > max) { + max = value; + } + } + } + } } - return a; + return max; }; -var min = function(array, f) { - var i = -1, - n = array.length, - a, - b; - - if (f == null) { - while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; } - while (++i < n) if ((b = array[i]) != null && a > b) a = b; +var min = function(values, valueof) { + var n = values.length, + i = -1, + value, + min; + + if (valueof == null) { + while (++i < n) { // Find the first comparable value. + if ((value = values[i]) != null && value >= value) { + min = value; + while (++i < n) { // Compare the remaining values. + if ((value = values[i]) != null && min > value) { + min = value; + } + } + } + } } else { - while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; } - while (++i < n) if ((b = f(array[i], i, array)) != null && a > b) a = b; - } - - return a; -}; - -var transpose = function(matrix) { - if (!(n = matrix.length)) return []; - for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) { - for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) { - row[j] = matrix[j][i]; + while (++i < n) { // Find the first comparable value. + if ((value = valueof(values[i], i, values)) != null && value >= value) { + min = value; + while (++i < n) { // Compare the remaining values. + if ((value = valueof(values[i], i, values)) != null && min > value) { + min = value; + } + } + } } } - return transpose; + + return min; }; function length(d) { @@ -2023,7 +2052,7 @@ var interpolateRgb = (function rgbGamma(y) { var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r), g = color$$1(start.g, end.g), b = color$$1(start.b, end.b), - opacity = color$$1(start.opacity, end.opacity); + opacity = nogamma(start.opacity, end.opacity); return function(t) { start.r = r(t); start.g = g(t); @@ -2485,6 +2514,14 @@ var formatGroup = function(grouping, thousands) { }; }; +var formatNumerals = function(numerals) { + return function(value) { + return value.replace(/[0-9]/g, function(i) { + return numerals[+i]; + }); + }; +}; + var formatDefault = function(x, p) { x = x.toPrecision(p); @@ -2545,9 +2582,11 @@ var formatTypes = { // [[fill]align][sign][symbol][0][width][,][.precision][type] var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i; -var formatSpecifier = function(specifier) { +function formatSpecifier(specifier) { return new FormatSpecifier(specifier); -}; +} + +formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof function FormatSpecifier(specifier) { if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier); @@ -2595,16 +2634,18 @@ FormatSpecifier.prototype.toString = function() { + this.type; }; -var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"]; - -function identity$3(x) { +var identity$3 = function(x) { return x; -} +}; + +var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"]; var formatLocale = function(locale) { var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3, currency = locale.currency, - decimal = locale.decimal; + decimal = locale.decimal, + numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3, + percent = locale.percent || "%"; function newFormat(specifier) { specifier = formatSpecifier(specifier); @@ -2622,7 +2663,7 @@ var formatLocale = function(locale) { // Compute the prefix and suffix. // For SI-prefix, the suffix is lazily computed. var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "", - suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : ""; + suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : ""; // What format function should we use? // Is this an integer type? @@ -2649,27 +2690,12 @@ var formatLocale = function(locale) { } else { value = +value; - // Convert negative to positive, and compute the prefix. - // Note that -0 is not less than 0, but 1 / -0 is! - var valueNegative = (value < 0 || 1 / value < 0) && (value *= -1, true); - // Perform the initial formatting. - value = formatType(value, precision); + var valueNegative = value < 0; + value = formatType(Math.abs(value), precision); - // If the original value was negative, it may be rounded to zero during - // formatting; treat this as (positive) zero. - if (valueNegative) { - i = -1, n = value.length; - valueNegative = false; - while (++i < n) { - if (c = value.charCodeAt(i), (48 < c && c < 58) - || (type === "x" && 96 < c && c < 103) - || (type === "X" && 64 < c && c < 71)) { - valueNegative = true; - break; - } - } - } + // If a negative value rounds to zero during formatting, treat as positive. + if (valueNegative && +value === 0) valueNegative = false; // Compute the prefix and suffix. valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix; @@ -2701,11 +2727,13 @@ var formatLocale = function(locale) { // Reconstruct the final output based on the desired alignment. switch (align) { - case "<": return valuePrefix + value + valueSuffix + padding; - case "=": return valuePrefix + padding + value + valueSuffix; - case "^": return padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); + case "<": value = valuePrefix + value + valueSuffix + padding; break; + case "=": value = valuePrefix + padding + value + valueSuffix; break; + case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break; + default: value = padding + valuePrefix + value + valueSuffix; break; } - return padding + valuePrefix + value + valueSuffix; + + return numerals(value); } format.toString = function() { @@ -4327,7 +4355,7 @@ function inferColumns(rows) { } var dsv = function(delimiter) { - var reFormat = new RegExp("[\"" + delimiter + "\n]"), + var reFormat = new RegExp("[\"" + delimiter + "\n\r]"), delimiterCode = delimiter.charCodeAt(0); function parse(text, f) { @@ -4447,7 +4475,7 @@ var tauEpsilon = tau - epsilon; function Path() { this._x0 = this._y0 = // start of current subpath this._x1 = this._y1 = null; // end of current subpath - this._ = []; + this._ = ""; } function path() { @@ -4457,22 +4485,22 @@ function path() { Path.prototype = path.prototype = { constructor: Path, moveTo: function(x, y) { - this._.push("M", this._x0 = this._x1 = +x, ",", this._y0 = this._y1 = +y); + this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y); }, closePath: function() { if (this._x1 !== null) { this._x1 = this._x0, this._y1 = this._y0; - this._.push("Z"); + this._ += "Z"; } }, lineTo: function(x, y) { - this._.push("L", this._x1 = +x, ",", this._y1 = +y); + this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y); }, quadraticCurveTo: function(x1, y1, x, y) { - this._.push("Q", +x1, ",", +y1, ",", this._x1 = +x, ",", this._y1 = +y); + this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y); }, bezierCurveTo: function(x1, y1, x2, y2, x, y) { - this._.push("C", +x1, ",", +y1, ",", +x2, ",", +y2, ",", this._x1 = +x, ",", this._y1 = +y); + this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y); }, arcTo: function(x1, y1, x2, y2, r) { x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r; @@ -4489,9 +4517,7 @@ Path.prototype = path.prototype = { // Is this path empty? Move to (x1,y1). if (this._x1 === null) { - this._.push( - "M", this._x1 = x1, ",", this._y1 = y1 - ); + this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1); } // Or, is (x1,y1) coincident with (x0,y0)? Do nothing. @@ -4501,9 +4527,7 @@ Path.prototype = path.prototype = { // Equivalently, is (x1,y1) coincident with (x2,y2)? // Or, is the radius zero? Line to (x1,y1). else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) { - this._.push( - "L", this._x1 = x1, ",", this._y1 = y1 - ); + this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1); } // Otherwise, draw an arc! @@ -4520,14 +4544,10 @@ Path.prototype = path.prototype = { // If the start tangent is not coincident with (x0,y0), line to. if (Math.abs(t01 - 1) > epsilon) { - this._.push( - "L", x1 + t01 * x01, ",", y1 + t01 * y01 - ); + this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01); } - this._.push( - "A", r, ",", r, ",0,0,", +(y01 * x20 > x01 * y20), ",", this._x1 = x1 + t21 * x21, ",", this._y1 = y1 + t21 * y21 - ); + this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21); } }, arc: function(x, y, r, a0, a1, ccw) { @@ -4544,42 +4564,35 @@ Path.prototype = path.prototype = { // Is this path empty? Move to (x0,y0). if (this._x1 === null) { - this._.push( - "M", x0, ",", y0 - ); + this._ += "M" + x0 + "," + y0; } // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0). else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) { - this._.push( - "L", x0, ",", y0 - ); + this._ += "L" + x0 + "," + y0; } // Is this arc empty? We’re done. if (!r) return; + // Does the angle go the wrong way? Flip the direction. + if (da < 0) da = da % tau + tau; + // Is this a complete circle? Draw two arcs to complete the circle. if (da > tauEpsilon) { - this._.push( - "A", r, ",", r, ",0,1,", cw, ",", x - dx, ",", y - dy, - "A", r, ",", r, ",0,1,", cw, ",", this._x1 = x0, ",", this._y1 = y0 - ); + this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0); } - // Otherwise, draw an arc! - else { - if (da < 0) da = da % tau + tau; - this._.push( - "A", r, ",", r, ",0,", +(da >= pi), ",", cw, ",", this._x1 = x + r * Math.cos(a1), ",", this._y1 = y + r * Math.sin(a1) - ); + // Is this arc non-empty? Draw an arc! + else if (da > epsilon) { + this._ += "A" + r + "," + r + ",0," + (+(da >= pi)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1)); } }, rect: function(x, y, w, h) { - this._.push("M", this._x0 = this._x1 = +x, ",", this._y0 = this._y1 = +y, "h", +w, "v", +h, "h", -w, "Z"); + this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z"; }, toString: function() { - return this._.join(""); + return this._; } }; @@ -4589,11 +4602,27 @@ var constant$5 = function(x) { }; }; +var abs = Math.abs; +var atan2 = Math.atan2; +var cos = Math.cos; +var max$1 = Math.max; +var min$1 = Math.min; +var sin = Math.sin; +var sqrt$1 = Math.sqrt; + var epsilon$1 = 1e-12; var pi$1 = Math.PI; var halfPi = pi$1 / 2; var tau$1 = 2 * pi$1; +function acos(x) { + return x > 1 ? 0 : x < -1 ? pi$1 : Math.acos(x); +} + +function asin(x) { + return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x); +} + function arcInnerRadius(d) { return d.innerRadius; } @@ -4614,10 +4643,6 @@ function arcPadAngle(d) { return d && d.padAngle; // Note: optional! } -function asin(x) { - return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x); -} - function intersect(x0, y0, x1, y1, x2, y2, x3, y3) { var x10 = x1 - x0, y10 = y1 - y0, x32 = x3 - x2, y32 = y3 - y2, @@ -4630,7 +4655,7 @@ function intersect(x0, y0, x1, y1, x2, y2, x3, y3) { function cornerTangents(x0, y0, x1, y1, r1, rc, cw) { var x01 = x0 - x1, y01 = y0 - y1, - lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), + lo = (cw ? rc : -rc) / sqrt$1(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x11 = x0 + ox, @@ -4644,7 +4669,7 @@ function cornerTangents(x0, y0, x1, y1, r1, rc, cw) { d2 = dx * dx + dy * dy, r = r1 - rc, D = x11 * y10 - x10 * y11, - d = (dy < 0 ? -1 : 1) * Math.sqrt(Math.max(0, r * r * d2 - D * D)), + d = (dy < 0 ? -1 : 1) * sqrt$1(max$1(0, r * r * d2 - D * D)), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, @@ -4927,21 +4952,6 @@ var circle = { } }; -var tan30 = Math.sqrt(1 / 3); -var tan30_2 = tan30 * 2; - -var ka = 0.89081309152928522810; -var kr = Math.sin(pi$1 / 10) / Math.sin(7 * pi$1 / 10); -var kx = Math.sin(tau$1 / 10) * kr; -var ky = -Math.cos(tau$1 / 10) * kr; - -var sqrt3 = Math.sqrt(3); - -var c = -0.5; -var s = Math.sqrt(3) / 2; -var k = 1 / Math.sqrt(12); -var a = (k / 2 + 1) * 3; - var noop$1 = function() {}; function point$2(that, x, y) { @@ -5721,11 +5731,6 @@ var stack = function() { return stack; }; -var ascending$2 = function(series) { - var sums = series.map(sum$1); - return none$2(series).sort(function(a, b) { return sums[a] - sums[b]; }); -}; - function sum$1(series) { var s = 0, i = -1, n = series.length, v; while (++i < n) if (v = +series[i][1]) s += v; @@ -5733,7 +5738,7 @@ function sum$1(series) { } // defined in rollup.config.js -var bucket = "chartprod"; +var bucket = "projects.buffalonews.com"; function debounce$1(fn, obj, timeout, root) { var timeoutID = -1; @@ -6051,24 +6056,9 @@ function isUndefined(val) { return val === undefined ? true : false; } -function arrayDiff(a1, a2) { - var o1 = {}, o2 = {}, diff = []; - for (var i = 0; i < a1.length; i++) { o1[a1[i]] = true; } - for (var i$1 = 0; i$1 < a2.length; i$1++) { o2[a2[i$1]] = true; } - for (var k in o1) { if (!(k in o2)) { diff.push(k); } } - for (var k$1 in o2) { if (!(k$1 in o1)) { diff.push(k$1); } } - return diff; -} -function arraySame(a1, a2) { - var ret = []; - for (var i in a1) { - if (a2.indexOf(a1[i]) > -1){ - ret.push(a1[i]); - } - } - return ret; -} + + @@ -6278,7 +6268,7 @@ function sleep(time) { if (time < Infinity) timeout = setTimeout(wake, delay); if (interval) interval = clearInterval(interval); } else { - if (!interval) interval = setInterval(poke, pokeDelay); + if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay); frame = 1, setFrame(wake); } } @@ -6630,7 +6620,7 @@ var transition_attr = function(name, value) { return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname) - : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value)); + : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value + "")); }; function attrTweenNS(fullname, value) { @@ -6899,7 +6889,7 @@ var transition_style = function(name, value, priority) { .on("end.style." + name, styleRemoveEnd(name)) : this.styleTween(name, typeof value === "function" ? styleFunction$1(name, i, tweenValue(this, "style." + name, value)) - : styleConstant$1(name, i, value), priority); + : styleConstant$1(name, i, value + ""), priority); }; function styleTween(name, value, priority) { @@ -7241,30 +7231,6 @@ var selection_properties = function(map) { return (typeof map === "function" ? propertiesFunction : propertiesObject)(this, map); }; -function attrsFunction$1(transition, map) { - return transition.each(function() { - var x = map.apply(this, arguments), t = select(this).transition(transition); - for (var name in x) t.attr(name, x[name]); - }); -} - -function attrsObject$1(transition, map) { - for (var name in map) transition.attr(name, map[name]); - return transition; -} - -function stylesFunction$1(transition, map, priority) { - return transition.each(function() { - var x = map.apply(this, arguments), t = select(this).transition(transition); - for (var name in x) t.style(name, x[name], priority); - }); -} - -function stylesObject$1(transition, map, priority) { - for (var name in map) transition.style(name, map[name], priority); - return transition; -} - selection.prototype.attrs = selection_attrs; selection.prototype.styles = selection_styles; selection.prototype.properties = selection_properties; @@ -7437,14 +7403,12 @@ var bottom = 3; var left = 4; var epsilon$2 = 1e-6; -function translateX(scale0, scale1, d) { - var x = scale0(d); - return "translate(" + (isFinite(x) ? x : scale1(d)) + ",0)"; +function translateX(x) { + return "translate(" + x + ",0)"; } -function translateY(scale0, scale1, d) { - var y = scale0(d); - return "translate(0," + (isFinite(y) ? y : scale1(d)) + ")"; +function translateY(y) { + return "translate(0," + y + ")"; } function center(scale) { @@ -7465,13 +7429,15 @@ function axis(orient, scale) { tickFormat = null, tickSizeInner = 6, tickSizeOuter = 6, - tickPadding = 3; + tickPadding = 3, + k = orient === top || orient === left ? -1 : 1, + x, y = orient === left || orient === right ? (x = "x", "y") : (x = "y", "x"), + transform = orient === top || orient === bottom ? translateX : translateY; function axis(context) { var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues, format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$5) : tickFormat, spacing = Math.max(tickSizeInner, 0) + tickPadding, - transform = orient === top || orient === bottom ? translateX : translateY, range = scale.range(), range0 = range[0] + 0.5, range1 = range[range.length - 1] + 0.5, @@ -7482,9 +7448,7 @@ function axis(orient, scale) { tickExit = tick.exit(), tickEnter = tick.enter().append("g").attr("class", "tick"), line = tick.select("line"), - text = tick.select("text"), - k = orient === top || orient === left ? -1 : 1, - x, y = orient === left || orient === right ? (x = "x", "y") : (x = "y", "x"); + text = tick.select("text"); path = path.merge(path.enter().insert("path", ".tick") .attr("class", "domain") @@ -7512,11 +7476,11 @@ function axis(orient, scale) { tickExit = tickExit.transition(context) .attr("opacity", epsilon$2) - .attr("transform", function(d) { return transform(position, this.parentNode.__axis || position, d); }); + .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); }); tickEnter .attr("opacity", epsilon$2) - .attr("transform", function(d) { return transform(this.parentNode.__axis || position, position, d); }); + .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); }); } tickExit.remove(); @@ -7528,7 +7492,7 @@ function axis(orient, scale) { tick .attr("opacity", 1) - .attr("transform", function(d) { return transform(position, position, d); }); + .attr("transform", function(d) { return transform(position(d)); }); line .attr(x + "2", k * tickSizeInner); @@ -8597,7 +8561,9 @@ function axisCleanup(node, obj, xAxisObj, yAxisObj) { // resets ranges and dimensions, redraws yAxis, redraws xAxis // …then redraws yAxis again if tick wrapping has changed xAxis height - axisManager(node, obj, yAxisObj.axis.scale(), 'yAxis'); + var newXAxisObj, newYAxisObj; + + newYAxisObj = axisManager(node, obj, yAxisObj.axis.scale(), 'yAxis'); var scaleObj = { rangeType: 'range', @@ -8610,7 +8576,7 @@ function axisCleanup(node, obj, xAxisObj, yAxisObj) { var prevXAxisHeight = obj.dimensions.xAxisHeight; - var newXAxisObj = axisManager(node, obj, xAxisObj.axis.scale(), 'xAxis'); + newXAxisObj = axisManager(node, obj, xAxisObj.axis.scale(), 'xAxis'); newXAxisObj.node .attr('transform', ("translate(" + (obj.dimensions.computedWidth() - obj.dimensions.tickWidth()) + ", " + (obj.dimensions.computedHeight() - obj.dimensions.xAxisHeight) + ")")); @@ -8620,9 +8586,17 @@ function axisCleanup(node, obj, xAxisObj, yAxisObj) { } if (prevXAxisHeight !== obj.dimensions.xAxisHeight) { - axisManager(node, obj, yAxisObj.axis.scale(), 'yAxis'); + newYAxisObj = axisManager(node, obj, yAxisObj.axis.scale(), 'yAxis'); } + // reset x-axis object values + xAxisObj.node = newXAxisObj.node; + xAxisObj.axis = newXAxisObj.axis; + + // reset y-axis object values + yAxisObj.node = newYAxisObj.node; + yAxisObj.axis = newYAxisObj.axis; + } function addZeroLine(obj, node, Axis, axisType) { @@ -10966,7 +10940,7 @@ var IE8_DOM_DEFINE = _ie8DomDefine; var toPrimitive = _toPrimitive; var dP$1 = Object.defineProperty; -var f$1 = _descriptors ? Object.defineProperty : function defineProperty(O, P, Attributes){ +var f = _descriptors ? Object.defineProperty : function defineProperty(O, P, Attributes){ anObject(O); P = toPrimitive(P, true); anObject(Attributes); @@ -10979,7 +10953,7 @@ var f$1 = _descriptors ? Object.defineProperty : function defineProperty(O, P, A }; var _objectDp = { - f: f$1 + f: f }; var _propertyDesc = function(bitmap, value){ @@ -11101,17 +11075,17 @@ var _toInteger = function(it){ // 7.1.15 ToLength var toInteger = _toInteger; -var min$1 = Math.min; +var min$2 = Math.min; var _toLength = function(it){ - return it > 0 ? min$1(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 + return it > 0 ? min$2(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 }; var toInteger$1 = _toInteger; -var max$1 = Math.max; -var min$2 = Math.min; +var max$2 = Math.max; +var min$3 = Math.min; var _toIndex = function(index, length){ index = toInteger$1(index); - return index < 0 ? max$1(index + length, 0) : min$2(index, length); + return index < 0 ? max$2(index + length, 0) : min$3(index, length); }; // false -> Array#indexOf @@ -11186,16 +11160,16 @@ var _objectKeys = Object.keys || function keys(O){ return $keys(O, enumBugKeys); }; -var f$2 = Object.getOwnPropertySymbols; +var f$1 = Object.getOwnPropertySymbols; var _objectGops = { - f: f$2 + f: f$1 }; -var f$3 = {}.propertyIsEnumerable; +var f$2 = {}.propertyIsEnumerable; var _objectPie = { - f: f$3 + f: f$2 }; // 7.1.13 ToObject(argument) diff --git a/meteor/lib/chart-tool/scripts/settings.js b/meteor/lib/chart-tool/scripts/settings.js index 6782aa2b..aa6fcf74 100644 --- a/meteor/lib/chart-tool/scripts/settings.js +++ b/meteor/lib/chart-tool/scripts/settings.js @@ -19,6 +19,7 @@ var bands = {"padding":0.12,"offset":0.06,"outerPadding":0.06}; var source = {"prefix":"CHART TOOL","suffix":" » SOURCE:"}; var social = {"facebook":{"label":"Facebook","icon":"https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-social-facebook.svg","redirect":"","appID":""},"twitter":{"label":"Twitter","icon":"https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-social-twitter.svg","via":"","hashtag":""},"email":{"label":"Email","icon":"https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-mail.svg"},"sms":{"label":"SMS","icon":"https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/fi-telephone.svg"}}; var image = {"enable":false,"base_path":"","expiration":30000,"filename":"thumbnail","extension":"png","thumbnailWidth":460}; +var slack = {"enable_webhooks":false,"username":"Chart tool","edit_address":"https://chart-tool-demo.herokuapp.com/chart/edit/"}; var embedJS = "http://beta.images.theglobeandmail.com/static/templates/tools/chart-tool/1.2.0/chart-tool.min.js"; var embedCSS = "http://beta.images.theglobeandmail.com/static/templates/tools/chart-tool/1.2.0/chart-tool.min.css"; var config = { @@ -43,6 +44,7 @@ var config = { source: source, social: social, image: image, + slack: slack, embedJS: embedJS, embedCSS: embedCSS }; @@ -60,6 +62,8 @@ app_settings = { s3: config.image, + slack: config.slack, + embedJS: config.embedJS, embedCSS: config.embedCSS, diff --git a/meteor/server/index.js b/meteor/server/index.js index b5e96420..250acace 100644 --- a/meteor/server/index.js +++ b/meteor/server/index.js @@ -2,7 +2,13 @@ Meteor.methods({ getAnimalName: function() { this.unblock(); return Meteor.http.get(app_settings.animal_api); - } + }, + postSlackMessage: function (slug, chartId) { + if (app_settings.slack.enable_webhooks) { + this.unblock(); + return Meteor.http.post(process.env.SLACK_WEBHOOK, {data: {'text': 'New chart alert, ' + slug + ' ' + app_settings.slack.edit_address + chartId, 'username': app_settings.slack.username}}) + } +} }); if (app_settings.s3.enable) { diff --git a/tutorials/slack-integration.md b/tutorials/slack-integration.md new file mode 100644 index 00000000..0aab1ffc --- /dev/null +++ b/tutorials/slack-integration.md @@ -0,0 +1,39 @@ +# Adding Slack to Chart Tool + +By adding your Slack team to Chart Tool, you can post messages when new charts are created. + + +---------- + +### Before you do anything +Create a private Testing channel so you don't overwhelm a channel and be *that person*. + +### **Step 1:** Create your Slack app +Go to [Slack's apps](https://api.slack.com/apps) and go through the process of creating a new app. You'll be asked for an App Name as well as the Development Slack Team, which is the team to post the messages. + +### **Step 2:** Activate the Incoming Webhooks feature +In the features section of your newly created app, click on the Incoming Webhooks section, and then toggle on this feature. + +### **Step 3:** Add New Webhook to Team +Click on the Add New Webhook to Team and choose the name of your testing channel. + +### **Step 4:** Save Webhook URL as environment variable. +Grab the Webhook Url and save it as SLACK_WEBHOOK in your environment variable. + +### **Step 5:** Enable Slack notifications under `chart-tool-config.json`. + +This is what `chart-tool-config.json` will look like by default: + +```javascript +"slack": { + "enable_webhooks": false, + "username": "Chart tool", + "edit_address": "https://chart-tool-demo.herokuapp.com/chart/edit/", +} +``` + +You'll need to tweak those options based on your Slack app. + +* `enable_webhooks`: Whether or not Slack notifications should be used. Change this to `true` +* `username`: Choose the username of the bot that posts the message. It should be the same name as the Slack app you created. +* `edit_address`: This is the base of the edit address so you need to customize it to your domain.