Skip to content
This repository was archived by the owner on Sep 10, 2021. It is now read-only.

Commit 53f6f83

Browse files
committed
ENH: refs #917. Add ability to delete a trend
1 parent b788c6f commit 53f6f83

File tree

8 files changed

+395
-5
lines changed

8 files changed

+395
-5
lines changed
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
(function($) {
2+
3+
// Class: $.jqplot.LinDifferentColorMarkerLineRenderereRenderer
4+
// Line renderer for jqPlot, this class has one
5+
// markerColors: []
6+
// Draws series as a line.
7+
$.jqplot.DifferentColorMarkerLineRenderer = function(options){
8+
this.markerColors = [];
9+
this.shapeRenderer = new $.jqplot.ShapeRenderer();
10+
this.shadowRenderer = new $.jqplot.ShadowRenderer();
11+
$.extend(true, this, options);
12+
};
13+
14+
// called with scope of series.
15+
$.jqplot.DifferentColorMarkerLineRenderer.prototype.init = function(options) {
16+
//$.extend(true, this, options);
17+
// set the shape renderer options
18+
this.markerColors = options.markerColors || this.markerColors;
19+
var opts = {
20+
lineJoin:'round',
21+
lineCap:'round',
22+
fill:this.fill,
23+
isarc:false,
24+
strokeStyle:this.color,
25+
fillStyle:this.fillColor,
26+
lineWidth:this.lineWidth,
27+
closePath:this.fill
28+
29+
};
30+
this.renderer.shapeRenderer.init(opts);
31+
// set the shadow renderer options
32+
// scale the shadowOffset to the width of the line.
33+
if (this.lineWidth > 2.5) {
34+
var shadow_offset = this.shadowOffset* (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6);
35+
// var shadow_offset = this.shadowOffset;
36+
}
37+
// for skinny lines, don't make such a big shadow.
38+
else {
39+
var shadow_offset = this.shadowOffset*Math.atan((this.lineWidth/2.5))/0.785398163;
40+
}
41+
var sopts = {
42+
lineJoin:'round',
43+
lineCap:'round',
44+
fill:this.fill,
45+
isarc:false,
46+
angle:this.shadowAngle,
47+
offset:shadow_offset,
48+
alpha:this.shadowAlpha,
49+
depth:this.shadowDepth,
50+
lineWidth:this.lineWidth,
51+
closePath:this.fill
52+
};
53+
this.renderer.shadowRenderer.init(sopts);
54+
};
55+
56+
// Method: setGridData
57+
// converts the user data values to grid coordinates and stores them
58+
// in the gridData array.
59+
// Called with scope of a series.
60+
$.jqplot.DifferentColorMarkerLineRenderer.prototype.setGridData = function(plot) {
61+
// recalculate the grid data
62+
var xp = this._xaxis.series_u2p;
63+
var yp = this._yaxis.series_u2p;
64+
var data = this._plotData;
65+
var pdata = this._prevPlotData;
66+
this.gridData = [];
67+
this._prevGridData = [];
68+
for (var i=0; i<this.data.length; i++) {
69+
if (data[i] != null) {
70+
this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
71+
}
72+
if (pdata[i] != null) {
73+
this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), yp.call(this._yaxis, pdata[i][1])]);
74+
}
75+
}
76+
};
77+
78+
// Method: makeGridData
79+
// converts any arbitrary data values to grid coordinates and
80+
// returns them. This method exists so that plugins can use a series'
81+
// linerenderer to generate grid data points without overwriting the
82+
// grid data associated with that series.
83+
// Called with scope of a series.
84+
$.jqplot.DifferentColorMarkerLineRenderer.prototype.makeGridData = function(data, plot) {
85+
// recalculate the grid data
86+
var xp = this._xaxis.series_u2p;
87+
var yp = this._yaxis.series_u2p;
88+
var gd = [];
89+
var pgd = [];
90+
for (var i=0; i<data.length; i++) {
91+
if (data[i] != null) {
92+
gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
93+
}
94+
}
95+
return gd;
96+
};
97+
98+
99+
// called within scope of series.
100+
$.jqplot.DifferentColorMarkerLineRenderer.prototype.draw = function(ctx, gd, options) {
101+
var i;
102+
var opts = (options != undefined) ? options : {};
103+
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
104+
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
105+
var fill = (opts.fill != undefined) ? opts.fill : this.fill;
106+
var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke;
107+
ctx.save();
108+
if (gd.length) {
109+
if (showLine) {
110+
// if we fill, we'll have to add points to close the curve.
111+
if (fill) {
112+
if (this.fillToZero) {
113+
// have to break line up into shapes at axis crossings
114+
var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
115+
var negativeColor = negativeColors.get(this.index);
116+
if (! this.useNegativeColors) {
117+
negativeColor = opts.fillStyle;
118+
}
119+
var isnegative = false;
120+
var posfs = opts.fillStyle;
121+
122+
// if stoking line as well as filling, get a copy of line data.
123+
if (fillAndStroke) {
124+
var fasgd = gd.slice(0);
125+
}
126+
// if not stacked, fill down to axis
127+
if (this.index == 0 || !this._stack) {
128+
129+
var tempgd = [];
130+
var pyzero = this._yaxis.series_u2p(0);
131+
var pxzero = this._xaxis.series_u2p(0);
132+
133+
if (this.fillAxis == 'y') {
134+
tempgd.push([gd[0][0], pyzero]);
135+
136+
for (var i=0; i<gd.length-1; i++) {
137+
tempgd.push(gd[i]);
138+
// do we have an axis crossing?
139+
if (this._plotData[i][1] * this._plotData[i+1][1] < 0) {
140+
if (this._plotData[i][1] < 0) {
141+
isnegative = true;
142+
opts.fillStyle = negativeColor;
143+
}
144+
else {
145+
isnegative = false;
146+
opts.fillStyle = posfs;
147+
}
148+
149+
var xintercept = gd[i][0] + (gd[i+1][0] - gd[i][0]) * (pyzero-gd[i][1])/(gd[i+1][1] - gd[i][1]);
150+
tempgd.push([xintercept, pyzero]);
151+
// now draw this shape and shadow.
152+
if (shadow) {
153+
this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
154+
}
155+
this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
156+
// now empty temp array and continue
157+
tempgd = [[xintercept, pyzero]];
158+
}
159+
}
160+
if (this._plotData[gd.length-1][1] < 0) {
161+
isnegative = true;
162+
opts.fillStyle = negativeColor;
163+
}
164+
else {
165+
isnegative = false;
166+
opts.fillStyle = posfs;
167+
}
168+
tempgd.push(gd[gd.length-1]);
169+
tempgd.push([gd[gd.length-1][0], pyzero]);
170+
}
171+
// now draw this shape and shadow.
172+
if (shadow) {
173+
this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
174+
}
175+
this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
176+
177+
178+
// var gridymin = this._yaxis.series_u2p(0);
179+
// // IE doesn't return new length on unshift
180+
// gd.unshift([gd[0][0], gridymin]);
181+
// len = gd.length;
182+
// gd.push([gd[len - 1][0], gridymin]);
183+
}
184+
// if stacked, fill to line below
185+
else {
186+
var prev = this._prevGridData;
187+
for (var i=prev.length; i>0; i--) {
188+
gd.push(prev[i-1]);
189+
}
190+
if (shadow) {
191+
this.renderer.shadowRenderer.draw(ctx, gd, opts);
192+
}
193+
194+
this.renderer.shapeRenderer.draw(ctx, gd, opts);
195+
}
196+
}
197+
else {
198+
// if stoking line as well as filling, get a copy of line data.
199+
if (fillAndStroke) {
200+
var fasgd = gd.slice(0);
201+
}
202+
// if not stacked, fill down to axis
203+
if (this.index == 0 || !this._stack) {
204+
// var gridymin = this._yaxis.series_u2p(this._yaxis.min) - this.gridBorderWidth / 2;
205+
var gridymin = ctx.canvas.height;
206+
// IE doesn't return new length on unshift
207+
gd.unshift([gd[0][0], gridymin]);
208+
len = gd.length;
209+
gd.push([gd[len - 1][0], gridymin]);
210+
}
211+
// if stacked, fill to line below
212+
else {
213+
var prev = this._prevGridData;
214+
for (var i=prev.length; i>0; i--) {
215+
gd.push(prev[i-1]);
216+
}
217+
}
218+
if (shadow) {
219+
this.renderer.shadowRenderer.draw(ctx, gd, opts);
220+
}
221+
222+
this.renderer.shapeRenderer.draw(ctx, gd, opts);
223+
}
224+
if (fillAndStroke) {
225+
var fasopts = $.extend(true, {}, opts, {
226+
fill:false,
227+
closePath:false
228+
});
229+
this.renderer.shapeRenderer.draw(ctx, fasgd, fasopts);
230+
//////////
231+
// TODO: figure out some way to do shadows nicely
232+
// if (shadow) {
233+
// this.renderer.shadowRenderer.draw(ctx, fasgd, fasopts);
234+
// }
235+
// now draw the markers
236+
if (this.markerRenderer.show) {
237+
for (i=0; i<fasgd.length; i++) {
238+
this.markerRenderer.draw(fasgd[i][0], fasgd[i][1], ctx, opts.markerOptions);
239+
}
240+
}
241+
}
242+
}
243+
else {
244+
if (shadow) {
245+
this.renderer.shadowRenderer.draw(ctx, gd, opts);
246+
}
247+
this.renderer.shapeRenderer.draw(ctx, gd, opts);
248+
}
249+
}
250+
251+
252+
// now draw the markers
253+
if (this.markerRenderer.show && !fill) {
254+
for (i=0; i<gd.length; i++) {
255+
// Grab each color and send it to a new markerRenderer.
256+
opts.markerOptions = {
257+
color: this.markerColors[i]
258+
};
259+
this.markerRenderer = new $.jqplot.MarkerRenderer
260+
this.markerRenderer.init(opts.markerOptions);
261+
this.markerRenderer.draw(gd[i][0], gd[i][1], ctx, opts.markerOptions);
262+
}
263+
}
264+
}
265+
266+
ctx.restore();
267+
};
268+
269+
$.jqplot.DifferentColorMarkerLineRenderer.prototype.drawShadow = function(ctx, gd, options) {
270+
// This is a no-op, shadows drawn with lines.
271+
};
272+
273+
})(jQuery);

modules/tracker/controllers/TrendController.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ public function viewAction()
7676
}
7777
$this->view->json['tracker']['scalars'][] = $this->Tracker_Trend->getScalars($trend, $startDate, $endDate, $userId);
7878
$this->view->json['tracker']['trends'][] = $trend;
79+
if(!isset($this->view->json['tracker']['producerId']))
80+
{
81+
$this->view->json['tracker']['producerId'] = $trend->getProducerId();
82+
}
7983
$this->view->trends[] = $trend;
8084
}
8185
if(isset($rightTrendId))
@@ -193,7 +197,22 @@ public function scalarsAction()
193197
*/
194198
public function deleteAction()
195199
{
196-
// TODO (include progress reporting)
200+
$this->disableLayout();
201+
$this->disableView();
202+
203+
$trendId = $this->_getParam('trendId');
204+
205+
if(!isset($trendId))
206+
{
207+
throw new Zend_Exception('Must pass trendId parameter');
208+
}
209+
$trend = $this->Tracker_Trend->load($trendId);
210+
$comm = $trend->getProducer()->getCommunity();
211+
if(!$this->Community->policyCheck($comm, $this->userSession->Dao, MIDAS_POLICY_ADMIN))
212+
{
213+
throw new Zend_Exception('Admin permission required on the community', 403);
214+
}
215+
$this->Tracker_Trend->delete($trend, $this->progressDao);
197216
}
198217

199218
/**

modules/tracker/models/base/ThresholdNotificationModelBase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function __construct()
4040

4141
public abstract function getNotifications($scalar);
4242
public abstract function getUserSetting($user, $trend);
43+
public abstract function deleteByTrend($trend);
4344

4445
/**
4546
* Check whether the given scalar value meets the threshold condition.

modules/tracker/models/base/TrendModelBase.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,35 @@ public function createIfNeeded($producerId, $metricName, $configItemId, $testDat
104104
/**
105105
* Delete the trend (deletes all child scalars as well)
106106
*/
107-
public function delete($trend)
107+
public function delete($trend, $progressDao = null)
108108
{
109109
$scalarModel = MidasLoader::loadModel('Scalar', $this->moduleName);
110+
$notificationModel = MidasLoader::loadModel('ThresholdNotification', $this->moduleName);
111+
if($progressDao)
112+
{
113+
$progressModel = MidasLoader::loadModel('Progress');
114+
$progressDao->setMessage('Counting scalar points...');
115+
$progressModel->save($progressDao);
116+
}
110117
$scalars = $trend->getScalars();
118+
if($progressDao)
119+
{
120+
$progressDao->setMaximum(count($scalars));
121+
$progressModel->save($progressDao);
122+
$i = 0;
123+
}
124+
111125
foreach($scalars as $scalar)
112126
{
127+
if($progressDao)
128+
{
129+
$i++;
130+
$message = 'Deleting scalars: '.$i.' of '.$progressDao->getMaximum();
131+
$progressModel->updateProgress($progressDao, $i, $message);
132+
}
113133
$scalarModel->delete($scalar);
114134
}
115-
// TODO delete all email notification thresholds for this trend
135+
$notificationModel->deleteByTrend($trend);
116136
parent::delete($trend);
117137
}
118138
}

modules/tracker/models/pdo/ThresholdNotificationModel.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,20 @@ public function getUserSetting($user, $trend)
4949
->where('recipient_id = ?', $user->getKey());
5050
return $this->initDao('ThresholdNotification', $this->database->fetchRow($sql), $this->moduleName);
5151
}
52+
53+
/**
54+
* Delete all thresholds for the given trend
55+
*/
56+
public function deleteByTrend($trend)
57+
{
58+
$sql = $this->database->select()
59+
->setIntegrityCheck(false)
60+
->where('trend_id= ?', $trend->getKey());
61+
$rows = $this->database->fetchAll($sql);
62+
foreach($rows as $row)
63+
{
64+
$threshold = $this->initDao('ThresholdNotification', $row, $this->moduleName);
65+
$this->delete($threshold);
66+
}
67+
}
5268
}

modules/tracker/public/css/trend/trend.view.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,17 @@ div.bottomButtons {
4848
margin-top: 15px;
4949
float: right;
5050
}
51+
52+
div.deleteProgressBar {
53+
margin-top: 10px;
54+
margin-bottom: 6px;
55+
}
56+
57+
div.bottomButtonsDelete {
58+
margin-top: 20px;
59+
float: right;
60+
}
61+
62+
input.deleteYes,input.deleteNo {
63+
margin-left: 10px !important;
64+
}

0 commit comments

Comments
 (0)