diff options
author | BeezyT <timo@ezdesign.de> | 2012-08-20 15:53:17 +0400 |
---|---|---|
committer | BeezyT <timo@ezdesign.de> | 2012-08-20 15:53:17 +0400 |
commit | 29fea18476fcad532e8a30c138e50bd4edc2e42d (patch) | |
tree | cde48618745486d510913d80a53f023124d147c1 /plugins/Transitions | |
parent | 4ed2a9de67412daae41492c2a558e1190642a25e (diff) |
refs #3332: Transitions UI (row action for pages report + popover)
git-svn-id: http://dev.piwik.org/svn/trunk@6844 59fd770c-687e-43c8-a1e3-f5a4ff64c105
Diffstat (limited to 'plugins/Transitions')
-rw-r--r-- | plugins/Transitions/Transitions.php | 2 | ||||
-rw-r--r-- | plugins/Transitions/templates/transitions.css | 110 | ||||
-rw-r--r-- | plugins/Transitions/templates/transitions.js | 751 | ||||
-rw-r--r-- | plugins/Transitions/templates/transitions.tpl | 40 | ||||
-rwxr-xr-x | plugins/Transitions/templates/transitions_rowaction.png | bin | 0 -> 269 bytes |
5 files changed, 901 insertions, 2 deletions
diff --git a/plugins/Transitions/Transitions.php b/plugins/Transitions/Transitions.php index 1073105681..3e0ccf5666 100644 --- a/plugins/Transitions/Transitions.php +++ b/plugins/Transitions/Transitions.php @@ -31,8 +31,6 @@ class Piwik_Transitions extends Piwik_Plugin function getListHooksRegistered() { return array( - 'ArchiveProcessing_Day.compute.Actions_PageUrlTable' => 'postArchiveDay', - 'ArchiveProcessing_Period.compute.Actions_PageUrlTable' => 'archivePeriod', 'AssetManager.getCssFiles' => 'getCssFiles', 'AssetManager.getJsFiles' => 'getJsFiles' ); diff --git a/plugins/Transitions/templates/transitions.css b/plugins/Transitions/templates/transitions.css new file mode 100644 index 0000000000..96dc572ea3 --- /dev/null +++ b/plugins/Transitions/templates/transitions.css @@ -0,0 +1,110 @@ + +#Transitions_Container { + position: relative; + z-index: 1500; + height: 550px; + text-align: left; +} + +#Transitions_Canvas { + position: absolute; + z-index: 1501; +} + +.Transitions_Text { + color: black; + font-size: 11px; + line-height: 14px; + position: absolute; + z-index: 1502; + font-family: Arial, Helvetica, sans-serif; + word-wrap: break-word; + text-align: left; +} + +#Transitions_CenterBox { + margin: 60px 0 0 320px; + width: 208px; + height: 270px; + background: #f7f7f7; + border: 1px solid #a9a399; + border-radius:10px; + -moz-border-radius:10px; + -webkit-border-radius:10px; + -webkit-box-shadow: 0px 0px 9px 0px #999; + -moz-box-shadow: 0px 0px 9px 0px #999; + box-shadow: 0px 0px 9px 0px #999; +} + +#Transitions_CenterBox.Transitions_Loading { + background: url(../../../themes/default/images/loading-blue.gif) no-repeat center center #f7f7f7; +} + +#Transitions_CenterBox h2 { + font-size: 12px; + line-height: 16px; + padding: 10px; + border-bottom: 1px dotted #a9a399; + font-weight: bold; + overflow: hidden; + color: #255792; +} + +.Transitions_CenterBoxMetrics { + padding: 15px 10px 0 10px; + display: none; + font-size: 12px; +} + +#Transitions_CenterBox h3 { + font-weight: bold; + font-size: 12px; + margin: 15px 0 7px 0; + padding: 0; + color: #7E7363; +} + +#Transitions_Loops { + margin: 360px 0 0 320px; + width: 208px; + text-align: center; + line-height: 25px; + font-size: 12px; + display: none; +} + +.Transitions_CenterBoxMetrics p { + margin: 0 0 5px 0; + padding: 0; +} + +.Transitions_CenterBoxMetrics p.Transitions_Margin { + margin-bottom: 11px; +} + +#Transitions_Loops .Transitions_Metric, +.Transitions_CenterBoxMetrics p .Transitions_Metric { + font-weight: bold; +} + +.Transitions_BoxTextLeft, +.Transitions_BoxTextRight { + width: 130px; + height: 42px; + overflow: hidden; +} + +.Transitions_BoxTextRight { + text-align: right; +} + +.Transitions_CurveText { + color: #255792; + font-weight: bold; + width: 25px; + text-align: right; +} + +.Transitions_SingleLine { + font-size: 12px; +}
\ No newline at end of file diff --git a/plugins/Transitions/templates/transitions.js b/plugins/Transitions/templates/transitions.js new file mode 100644 index 0000000000..75db309f30 --- /dev/null +++ b/plugins/Transitions/templates/transitions.js @@ -0,0 +1,751 @@ +/*! + * Piwik - Web Analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + + +// +// TRANSITIONS ROW ACTION FOR DATA TABLES +// + +function DataTable_RowActions_Transitions(dataTable) { + this.dataTable = dataTable; + this.transitions = null; +} + +DataTable_RowActions_Transitions.prototype = new DataTable_RowAction; + +// override trigger method directly because we don't need the label +DataTable_RowActions_Transitions.prototype.trigger = function(tr, e, subTableLabel) { + var link = tr.find('> td:first > a').attr('href'); + link = $('<textarea>').html(link).val(); // remove html entities + this.openPopover(link); +}; + +DataTable_RowActions_Transitions.prototype.doOpenPopover = function(link) { + if (this.transitions === null) { + this.transitions = new Piwik_Transitions(link, this); + } else { + this.transitions.reset(link); + } + this.transitions.showPopover(); +}; + + +DataTable_RowActions_Registry.register({ + + name: 'Transitions', + + dataTableIcon: 'plugins/Transitions/templates/transitions_rowaction.png', + + createInstance: function(dataTable) { + return new DataTable_RowActions_Transitions(dataTable); + }, + + isAvailable: function(dataTableParams, tr) { + return dataTableParams.module == 'Actions' + && dataTableParams.action == 'getPageUrls' + && tr.find('> td:first > a').size() > 0; + } + +}); + + +// +// TRANSITIONS IMPLEMENTATION +// + +function Piwik_Transitions(link, rowAction) { + this.reset(link); + this.rowAction = rowAction; + + this.ajax = new Piwik_Transitions_Ajax(); + this.model = new Piwik_Transitions_Model(this.ajax); +} + +Piwik_Transitions.prototype.reset = function(link) { + this.link = link; + + this.popover = null; + this.canvas = null; + this.centerBox = null; +}; + +/** Open the popover */ +Piwik_Transitions.prototype.showPopover = function() { + var self = this; + + // initialize popover (with loading message) + var loading = $('div.loadingPiwik:first').clone(); + var box = $(document.createElement('div')).attr('id', 'Transitions_Popover').html(loading); + box.dialog({ + title: '', + modal: true, + width: '900px', + position: ['center', 'center'], + resizable: false, + autoOpen: true, + close: function(event, ui) { + box.dialog('destroy').remove(); + } + }); + this.popover = box; + + // load the popover HTML + this.ajax.callTransitionsController('renderPopover', function(html) { + box.html(html); + box.dialog({position: ['center', 'center']}); + + var canvasDom = box.find('#Transitions_Canvas')[0]; + self.canvas = new Piwik_Transitions_Canvas(canvasDom, 850, 550); + + self.centerBox = box.find('#Transitions_CenterBox'); + + self.centerBox.find('h2').html(self.addBreakpoints(self.link)); + + self.model.loadData(self.link, function() { + self.render(); + }); + }); +}; + +/** Add break points to string so that it can be displayed more compactly */ +Piwik_Transitions.prototype.addBreakpoints = function(text) { + return text.replace(/([\/&=?\.%#:])/g, '$1<wbr>'); +}; + +/** Render the popover content */ +Piwik_Transitions.prototype.render = function() { + this.renderCenterBox(); + + this.renderEntriesAndExits(); + + this.renderPreviousPages(); + this.renderFollowingPages(); + + this.renderReferrers(); + + this.renderLoops(); +}; + +Piwik_Transitions.prototype.renderCenterBox = function() { + var box = this.centerBox; + box.removeClass('Transitions_Loading'); + + box.find('.Transitions_Pageviews').html(this.model.pageviews); + + var self = this; + var showMetric = function(cssClass, modelProperty) { + box.find('.Transitions_' + cssClass).html(self.model[modelProperty]); + box.find('.Transitions_' + cssClass + 'Percentage').html(self.model.getPercentage(modelProperty, true)); + }; + + showMetric('DirectEntries', 'directEntries'); + showMetric('SearchEngines', 'searchEngineReferrals'); + showMetric('Websites', 'websiteReferrals'); + + showMetric('Exits', 'exits'); + showMetric('Bounces', 'bounces'); + + box.find('.Transitions_CenterBoxMetrics').show(); +}; + +Piwik_Transitions.prototype.renderLoops = function() { + if (this.model.loops == 0) { + return; + } + this.popover.find('.Transitions_Loops').html(this.model.loops); + this.popover.find('.Transitions_LoopsPercentage').html(this.model.getPercentage('loops', true)); + this.popover.find('#Transitions_Loops').show(); + this.canvas.renderLoops(this.model.getPercentage('loops')); +}; + +Piwik_Transitions.prototype.renderEntriesAndExits = function() { + if (this.model.directEntries > 0) { + this.canvas.renderBoxLeft({ + share: this.model.getPercentage('directEntries'), + gradient: this.canvas.createHorizontalGradient('#CFEDCA', '#91DE83', 'left'), + boxText: 'Direct entries', + boxTextNumLines: 1, + boxTextCssClass: 'SingleLine', + smallBox: true + }); + this.canvas.addBoxSpacing(20, 'left'); + } + + if (this.model.exits > 0) { + this.canvas.renderBoxRight({ + share: this.model.getPercentage('exits'), + gradient: this.canvas.createHorizontalGradient('#EBCDCC', '#D98E8D', 'right'), + boxText: 'Exits', + boxTextNumLines: 1, + boxTextCssClass: 'SingleLine', + smallBox: true + }); + this.canvas.addBoxSpacing(20, 'right'); + } +}; + +Piwik_Transitions.prototype.renderPreviousPages = function() { + this.renderPages(this.model.getPreviousPages(), 'left'); +}; + +Piwik_Transitions.prototype.renderFollowingPages = function() { + this.renderPages(this.model.getFollowingPages(), 'right'); +}; + +Piwik_Transitions.prototype.renderPages = function(pagesData, side) { + var self = this; + var gradientPages = this.canvas.createHorizontalGradient('#F5F4F0', '#CFCBB6', side); + var gradientOthers = this.canvas.createHorizontalGradient('#F5F4F0', '#E3E1D5', side); + + var totalShare = this.model.getPercentage(side == 'left' ? 'internalTrafficIn' : 'internalTrafficOut'); + totalShare -= this.model.getPercentage('loops'); + + for (var i = 0; i < pagesData.length; i++) { + var pageData = pagesData[i]; + + var isOthers = pageData.url == 'Others'; + if (isOthers) { + this.canvas.addBoxSpacing(10, side); + } + + var params = { + share: pageData.percentage / 100 * totalShare, + gradient: isOthers ? gradientOthers : gradientPages, + boxText: pageData.url + ' (' + pageData.referrals + ')', + boxTextNumLines: 3, + curveText: pageData.percentage + '%', + onClick: (function(url) { + return function() { self.reloadPopover(url) }; + })(pageData.url) + }; + + if (side == 'left') { + this.canvas.renderBoxLeft(params); + } else { + this.canvas.renderBoxRight(params); + } + } +}; + +Piwik_Transitions.prototype.renderReferrers = function() { + var self = this; + var gradient = this.canvas.createHorizontalGradient('#DDE4ED', '#9BBADE', 'left'); + this.canvas.addBoxSpacing(20, 'left'); + + var renderBox = function(modelVariable, text) { + if (self.model[modelVariable] == 0) { + return; + } + self.canvas.renderBoxLeft({ + share: self.model.getPercentage(modelVariable), + gradient: gradient, + boxText: text, + boxTextNumLines: 1, + boxTextCssClass: 'SingleLine', + smallBox: true + }); + }; + + renderBox('searchEngineReferrals', 'From Search Engines'); + renderBox('websiteReferrals', 'From other Websites'); + renderBox('campaignReferrals', 'From Campaigns'); +}; + +Piwik_Transitions.prototype.reloadPopover = function(link) { + this.popover.dialog('close'); + this.rowAction.openPopover(link); +}; + + +// -------------------------------------- +// CANVAS +// -------------------------------------- + +function Piwik_Transitions_Canvas(canvasDom, width, height) { + if (!canvasDom.getContext) { + alert('Your browser is not supported.'); + return; + } + + /** DOM element that contains the canvas */ + this.container = $(canvasDom).parent(); + /** Drawing context of the canvas */ + this.context = canvasDom.getContext('2d'); + + /** Width of the entire canvas */ + this.width = canvasDom.width = width; + /** Height of the entire canvas */ + this.height = canvasDom.height = height; + + /** Current Y positions */ + this.leftBoxPositionY = 0; + this.leftCurvePositionY = 110; + this.rightBoxPositionY = 0; + this.rightCurvePositionY = 110; + + /** Width of the rectangular box */ + this.boxWidth = 140; + /** Height of the rectangular box */ + this.boxHeight = 53; + /** Height of a smaller rectangular box */ + this.smallBoxHeight = 30; + /** Width of the curve that connects the boxes to the center */ + this.curveWidth = 180; + /** Line-height of the text */ + this.lineHeight = 14; + /** Spacing between rectangular boxes */ + this.boxSpacing = 7; + /** Spacing between the curves where they connect to the center */ + this.curveSpacing = 2; + + /** The total net height (without curve spacing) of the curves as they connect to the center */ + this.totalHeightOfConnections = 170; + + /** X positions of the left box - begin means left, end means right */ + this.leftBoxBeginX = 0; + this.leftBoxEndX = this.leftCurveBeginX = this.leftBoxBeginX + this.boxWidth; + this.leftCurveEndX = this.leftCurveBeginX + this.curveWidth; + + /** X positions of the right box - begin means left, end means right */ + this.rightBoxEndX = this.width; + this.rightBoxBeginX = this.rightCurveEndX = this.rightBoxEndX - this.boxWidth; + this.rightCurveBeginX = this.rightCurveEndX - this.curveWidth; +} + +/** + * Helper to create horizontal gradients + * @param position left|right + */ +Piwik_Transitions_Canvas.prototype.createHorizontalGradient = function(lightColor, darkColor, position) { + var fromX, toX, fromColor, toColor; + + if (position == 'left') { + // gradient is used to fill a box on the left + fromX = this.leftBoxBeginX + 50; + toX = this.leftCurveEndX - 20; + fromColor = lightColor; + toColor = darkColor; + } else { + // gradient is used to fill a box on the right + fromX = this.rightCurveBeginX + 20; + toX = this.rightBoxEndX - 50; + fromColor = darkColor; + toColor = lightColor; + } + + var gradient = this.context.createLinearGradient(fromX, 0, toX, 0); + gradient.addColorStop(0, fromColor); + gradient.addColorStop(1, toColor); + + return gradient; +}; + +/** Render text using a div inside the container */ +Piwik_Transitions_Canvas.prototype.renderText = function(text, x, y, cssClass, onClick) { + var div = this.addDomElement('div', 'Text'); + div.html(Piwik_Transitions.prototype.addBreakpoints(text)); + div.css({ + left: x + 'px', + top: y + 'px' + }); + if (cssClass) { + div.addClass('Transitions_' + cssClass); + } + if (onClick) { + div.css('cursor', 'pointer').hover(function() { + $(this).addClass('Transitions_Hover'); + }, function() { + $(this).removeClass('Transitions_Hover'); + }).click(onClick); + } + return div; +}; + +/** Add a DOM element inside the container (as a sibling of the canvas) */ +Piwik_Transitions_Canvas.prototype.addDomElement = function(tagName, cssClass) { + var el = $(document.createElement('div')).addClass('Transitions_' + cssClass); + this.container.append(el); + return el; +}; + +/** + * Render a box on the left hand side. + * This method automatically keeps track of the current position. + * + * OPTIONS (pass as object) + * share: of the box in the total amount of incoming transitions + * gradient: for filling the box + * boxText: to be placed inside the box + * boxTextNumLines: the number of lines to be placed in the box + * boxTextCssClass: for divs containing the texts (optional) + * curveText: to be placed where the curve begins (optional) + * smallBox: use this.smallBoxHeight instead of this.boxHeight (optional) + */ +Piwik_Transitions_Canvas.prototype.renderBoxLeft = function(params) { + var curveHeight = Math.round(this.totalHeightOfConnections * params.share); + curveHeight = Math.max(curveHeight, 1); + + var boxHeight = params.smallBox ? this.smallBoxHeight : this.boxHeight; + + // DRAW BACKGROUND + this.context.fillStyle = params.gradient; + + // derive coordinates for ths curve + var leftUpper = {x: this.leftCurveBeginX, y: this.leftBoxPositionY}; + var leftLower = {x: this.leftCurveBeginX, y: this.leftBoxPositionY + boxHeight}; + var rightUpper = {x: this.leftCurveEndX, y: this.leftCurvePositionY}; + var rightLower = {x: this.leftCurveEndX, y: this.leftCurvePositionY + curveHeight}; + + // derive control points for bezier curve + var center = (this.leftCurveBeginX + this.leftCurveEndX) / 2; + var cp1Upper = {x: center, y: leftUpper.y}; + var cp2Upper = {x: center, y: rightUpper.y}; + var cp1Lower = {x: center, y: rightLower.y}; + var cp2Lower = {x: center, y: leftLower.y}; + + this.context.beginPath(); + + // the flow + this.context.moveTo(leftUpper.x, leftUpper.y); + this.context.bezierCurveTo(cp1Upper.x, cp1Upper.y, cp2Upper.x, cp2Upper.y, rightUpper.x, rightUpper.y); + this.context.lineTo(rightLower.x, rightLower.y); + this.context.bezierCurveTo(cp1Lower.x, cp1Lower.y, cp2Lower.x, cp2Lower.y, leftLower.x, leftLower.y); + + // the box + this.context.lineTo(leftLower.x - this.boxWidth + 4, leftLower.y); + this.context.lineTo(leftLower.x - this.boxWidth, leftUpper.y); + this.context.lineTo(leftUpper.x, leftUpper.y); + this.context.fill(); + + if (typeof this.context.endPath == 'function') { + this.context.endPath(); + } + + + // ADD TEXT + + // inside box + var boxTextLeft = this.leftBoxBeginX + 10; + var boxTextTop = this.leftBoxPositionY + boxHeight / 2 - params.boxTextNumLines * this.lineHeight / 2; + var onClick = typeof params.onClick == 'function' ? params.onClick : false; + var el = this.renderText(params.boxText, boxTextLeft, boxTextTop, 'BoxTextLeft', onClick); + if (params.boxTextCssClass) { + el.addClass('Transitions_' + params.boxTextCssClass); + } + + // at the beginning of the curve + if (params.curveText) { + var curveTextLeft = this.leftBoxBeginX + this.boxWidth + 12; + var curveTextTop = this.leftBoxPositionY + boxHeight / 2 - this.lineHeight / 2; + this.renderText(params.curveText, curveTextLeft, curveTextTop, 'CurveText'); + } + + + this.leftBoxPositionY += boxHeight + this.boxSpacing; + this.leftCurvePositionY += curveHeight + this.curveSpacing; +}; + +/** + * Render a box on the right hand side. + * This method automatically keeps track of the current position. + * + * OPTIONS (pass as object) + * share: of the box in the total amount of incoming transitions + * gradient: for filling the box + * boxText: to be placed inside the box + * boxTextNumLines: the number of lines to be placed in the box + * boxTextCssClass: for divs containing the texts (optional) + * curveText: to be placed where the curve begins (optional) + */ +Piwik_Transitions_Canvas.prototype.renderBoxRight = function(params) { + var curveHeight = Math.round(this.totalHeightOfConnections * params.share); + curveHeight = Math.max(curveHeight, 1); + + var boxHeight = params.smallBox ? this.smallBoxHeight : this.boxHeight; + + // DRAW BACKGROUND + this.context.fillStyle = params.gradient; + + // derive coordinates for curve + var leftUpper = {x: this.rightCurveBeginX, y: this.rightCurvePositionY}; + var leftLower = {x: this.rightCurveBeginX, y: this.rightCurvePositionY + curveHeight}; + var rightUpper = {x: this.rightCurveEndX, y: this.rightBoxPositionY}; + var rightLower = {x: this.rightCurveEndX, y: this.rightBoxPositionY + boxHeight}; + + // derive control points for bezier curve + var center = (this.rightCurveBeginX + this.rightCurveEndX) / 2; + var cp1Upper = {x: center, y: leftUpper.y}; + var cp2Upper = {x: center, y: rightUpper.y}; + var cp1Lower = {x: center, y: rightLower.y}; + var cp2Lower = {x: center, y: leftLower.y}; + + this.context.beginPath(); + + // the flow part 1 + this.context.moveTo(leftUpper.x, leftUpper.y); + this.context.bezierCurveTo(cp1Upper.x, cp1Upper.y, cp2Upper.x, cp2Upper.y, rightUpper.x, rightUpper.y); + + // the box + this.context.lineTo(rightUpper.x + this.boxWidth, rightUpper.y); + this.context.lineTo(rightLower.x + this.boxWidth - 4, rightLower.y); + this.context.lineTo(rightLower.x, rightLower.y); + + // the flow part 2 + this.context.bezierCurveTo(cp1Lower.x, cp1Lower.y, cp2Lower.x, cp2Lower.y, leftLower.x, leftLower.y); + this.context.lineTo(leftUpper.x, leftUpper.y); + this.context.fill(); + + if (typeof this.context.endPath == 'function') { + this.context.endPath(); + } + + + // ADD TEXT + + // inside box + var boxTextLeft = this.rightBoxBeginX; + var boxTextTop = this.rightBoxPositionY + boxHeight / 2 - params.boxTextNumLines * this.lineHeight / 2; + var onClick = typeof params.onClick == 'function' ? params.onClick : false; + var el = this.renderText(params.boxText, boxTextLeft, boxTextTop, 'BoxTextRight', onClick); + if (params.boxTextCssClass) { + el.addClass('Transitions_' + params.boxTextCssClass); + } + + // at the beginning of the curve + if (params.curveText) { + var curveTextLeft = this.rightBoxBeginX - 35; + var curveTextTop = this.rightBoxPositionY + boxHeight / 2 - this.lineHeight / 2; + this.renderText(params.curveText, curveTextLeft, curveTextTop, 'CurveText'); + } + + + this.rightBoxPositionY += boxHeight + this.boxSpacing; + this.rightCurvePositionY += curveHeight + this.curveSpacing; +}; + +/** Add spacing after the current box */ +Piwik_Transitions_Canvas.prototype.addBoxSpacing = function(spacing, side) { + if (side == 'left') { + this.leftBoxPositionY += spacing; + } else { + this.rightBoxPositionY += spacing; + } +}; + +Piwik_Transitions_Canvas.prototype.renderLoops = function(share) { + var curveHeight = Math.round(this.totalHeightOfConnections * share); + curveHeight = Math.max(curveHeight, 1); + + // create gradient + var gradient = this.context.createLinearGradient(this.leftCurveEndX - 50, 0, this.rightCurveBeginX + 50, 0); + var light = '#F5F4F0'; + var dark = '#E3E1D5'; + gradient.addColorStop(0, dark); + gradient.addColorStop(.5, light); + gradient.addColorStop(1, dark); + + this.context.fillStyle = gradient; + + this.context.beginPath(); + + // curve from the upper left connection to the center box to the lower left connection to the text box + var point1 = {x: this.leftCurveEndX, y: this.leftCurvePositionY}; + var point2 = {x: this.leftCurveEndX, y: 385}; + + var cpLeftX = (this.leftCurveBeginX + this.leftCurveEndX) / 2 + 30; + var cp1 = {x: cpLeftX, y: point1.y}; + var cp2 = {x: cpLeftX, y: point2.y}; + + this.context.moveTo(point1.x, point1.y); + this.context.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, point2.x, point2.y); + + // lower line of text box + var point3 = {x: this.rightCurveBeginX, y: point2.y}; + this.context.lineTo(point3.x, point3.y); + + // curve to upper right connection to the center box + var point4 = {x: this.rightCurveBeginX, y: this.rightCurvePositionY}; + var cpRightX = (this.rightCurveBeginX + this.rightCurveEndX) / 2 - 30; + var cp3 = {x: cpRightX, y: point3.y}; + var cp4 = {x: cpRightX, y: point4.y}; + this.context.bezierCurveTo(cp3.x, cp3.y, cp4.x, cp4.y, point4.x, point4.y); + + // line to lower right connection to the center box + var point5 = {x: point4.x, y: point4.y + curveHeight}; + this.context.lineTo(point5.x, point5.y); + + // curve to upper right connection to the text box + var point6 = {x: point5.x, y: point2.y - 25}; + cpRightX -= 30; + var cp5 = {x: cpRightX, y: point5.y}; + var cp6 = {x: cpRightX, y: point6.y}; + this.context.bezierCurveTo(cp5.x, cp5.y, cp6.x, cp6.y, point6.x, point6.y); + + // upper line of the text box + var point7 = {x: point1.x, y: point6.y}; + this.context.lineTo(point7.x, point7.y); + + // line to lower left connection to the center box + var point8 = {x: point1.x, y: point1.y + + curveHeight}; + cpLeftX += 30; + var cp7 = {x: cpLeftX, y: point7.y}; + var cp8 = {x: cpLeftX, y: point8.y}; + this.context.bezierCurveTo(cp7.x, cp7.y, cp8.x, cp8.y, point8.x, point8.y); + + this.context.fill(); + + if (typeof this.context.endPath == 'function') { + this.context.endPath(); + } + +}; + + +// -------------------------------------- +// MODEL +// -------------------------------------- + +function Piwik_Transitions_Model(ajax) { + this.ajax = ajax; +} + +Piwik_Transitions_Model.prototype.loadData = function(link, callback) { + var self = this; + + this.pageviews = 0; + this.exits = 0; + this.bounces = 0; + this.loops = 0; + + this.internalTrafficIn = 0; + this.internalTrafficOut = 0; + + this.directEntries = 0; + this.searchEngineReferrals = 0; + this.websiteReferrals = 0; + this.campaignReferrals = 0; + + this.followingPages = []; + this.previousPages = []; + + this.ajax.callApi('Transitions.getFullReport', { + pageUrl: link, + expanded: 1 + }, + function(report) { + console.log(report); + // load page metrics + self.pageviews = report.pageMetrics.pageviews; + self.exits = report.pageMetrics.exits; + self.bounces = report.pageMetrics.bounces; + self.loops = report.pageMetrics.loops; + self.internalTrafficIn = report.pageMetrics.internalTrafficIn; + self.internalTrafficOut = report.pageMetrics.internalTrafficOut; + + // load referrers: split direct entries and others + for (var i = 0; i < report.referrers.length; i++) { + var referrer = report.referrers[i]; + if (referrer.shortName == 'direct') { + self.directEntries = referrer.visits; + } else if (referrer.shortName == 'search') { + self.searchEngineReferrals = referrer.visits; + } else if (referrer.shortName == 'website') { + self.websiteReferrals = referrer.visits; + } else if (referrer.shortName == 'campaign') { + self.campaignReferrals = referrer.visits; + } + } + + // load previous and following pages + self.previousPages = report.previousPages; + self.followingPages = report.followingPages; + + callback(); + }); +}; + +Piwik_Transitions_Model.prototype.getPercentage = function(metric, formatted) { + var percentage = (this.pageviews == 0 ? 0 : this[metric] / this.pageviews); + + if (formatted) { + percentage = this.roundPercentage(percentage); + percentage += '%'; + } + + return percentage; +}; + +Piwik_Transitions_Model.prototype.getPreviousPages = function() { + var total = 0; + for (var i = 0; i < this.previousPages.length; i++) { + total += parseInt(this.previousPages[i].referrals, 10); + } + + for (var i = 0; i < this.previousPages.length; i++) { + this.previousPages[i].percentage = this.roundPercentage(this.previousPages[i].referrals / total); + } + + return this.previousPages; +}; + +Piwik_Transitions_Model.prototype.getFollowingPages = function() { + var total = 0; + + for (var i = 0; i < this.followingPages.length; i++) { + total += parseInt(this.followingPages[i].referrals, 10); + } + + for (var i = 0; i < this.followingPages.length; i++) { + this.followingPages[i].percentage = this.roundPercentage(this.followingPages[i].referrals / total); + } + + return this.followingPages; +}; + +Piwik_Transitions_Model.prototype.roundPercentage = function(value) { + if (value < .1) { + return Math.round(value * 1000) / 10.0; + } else { + return Math.round(value * 100); + } +}; + + +// -------------------------------------- +// AJAX +// -------------------------------------- + +function Piwik_Transitions_Ajax() { +} + +Piwik_Transitions_Ajax.prototype.callTransitionsController = function(action, callback) { + $.post('index.php', { + module: 'Transitions', + action: action, + date: piwik.currentDateString, + idSite: piwik.idSite, + period: piwik.period + }, callback); +}; + +Piwik_Transitions_Ajax.prototype.callApi = function(method, params, callback) { + params.module = 'API'; + params.method = method; + params.date = piwik.currentDateString; + params.idSite = piwik.idSite; + params.period = piwik.period; + params.token_auth = piwik.token_auth; + params.format = 'JSON'; + + $.post('index.php', params, function(result) { + if (typeof result.result != 'undefined' && result.result == 'error') { + alert(result.message); + } else { + callback(result); + } + }, 'json'); +}; diff --git a/plugins/Transitions/templates/transitions.tpl b/plugins/Transitions/templates/transitions.tpl new file mode 100644 index 0000000000..5c9ad2d04d --- /dev/null +++ b/plugins/Transitions/templates/transitions.tpl @@ -0,0 +1,40 @@ + +<div id="Transitions_Container"> + <div id="Transitions_CenterBox" class="Transitions_Text Transitions_Loading"> + <h2></h2> + <div class="Transitions_CenterBoxMetrics"> + <p class="Transitions_Margin"> + <span class="Transitions_Pageviews Transitions_Metric"></span> {'General_ColumnPageviews'|translate} + </p> + + <h3>{'Transitions_IncomingTraffic'|translate}</h3> + <p> + <span class="Transitions_DirectEntries Transitions_Metric"></span> {'Referers_TypeDirectEntries'|translate:''} + (<span class="Transitions_DirectEntriesPercentage"></span>) + </p> + <p> + <span class="Transitions_SearchEngines Transitions_Metric"></span> {'Referers_TypeSearchEngines'|translate:''} + (<span class="Transitions_SearchEnginesPercentage"></span>) + </p> + <p> + <span class="Transitions_Websites Transitions_Metric"></span> {'Referers_TypeWebsites'|translate:''} + (<span class="Transitions_WebsitesPercentage"></span>) + </p> + + <h3>{'Transitions_OutgoingTraffic'|translate}</h3> + <p> + <span class="Transitions_Exits Transitions_Metric"></span> {'General_ColumnExits'|translate} + (<span class="Transitions_ExitsPercentage"></span>), {'Transitions_Including'|translate} + </p> + <p> + <span class="Transitions_Bounces Transitions_Metric"></span> {'General_ColumnBounces'|translate} + (<span class="Transitions_BouncesPercentage"></span>) + </p> + </div> + </div> + <div id="Transitions_Loops" class="Transitions_Text"> + <span class="Transitions_Loops Transitions_Metric"></span> {'Transitions_Loops'|translate} + (<span class="Transitions_LoopsPercentage"></span>) + </div> + <canvas id="Transitions_Canvas"></canvas> +</div>
\ No newline at end of file diff --git a/plugins/Transitions/templates/transitions_rowaction.png b/plugins/Transitions/templates/transitions_rowaction.png Binary files differnew file mode 100755 index 0000000000..5e31bbe260 --- /dev/null +++ b/plugins/Transitions/templates/transitions_rowaction.png |