Skip to content

Commit 47446dc

Browse files
authored
Merge pull request #52 from chaitanyya/master
Added Public View
2 parents fb434ac + 2109c34 commit 47446dc

File tree

14 files changed

+501
-70
lines changed

14 files changed

+501
-70
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# Dotplot - Telling a story through dots
22

3-
DotPlot is a data visualisation tool built on top of [D3.js](https://d3js.org/) to help non-programmers create interactive data visualisations using easy to use drag and drop interface.
3+
DotPlot is a data visualisation tool built on top of [D3.js](https://d3js.org/) to help non-programmers create interactive data visualisations using easy to use drag and drop interface.
44

5+
### Create View (Create or Edit DotPlot Projects)
56
![DotPlot App Screenshot](/public/assets/docs/screenshot.png?raw=true)
67

8+
### Presentation View (Share or Present DotPlot Projects)
9+
![DotPlot Presentation Screenshot](/public/assets/docs/screenshot2.png?raw=true)
10+
711
## Prerequisites
812

913
To contribute to this project, you will need the following things properly installed on your computer.
@@ -25,6 +29,7 @@ To contribute to this project, you will need the following things properly insta
2529

2630
* `ember server`
2731
* Visit your app at [http://localhost:4200/create](http://localhost:4200/create).
32+
* Public View: `http://localhost:4200/project?id=<Your Project Id>`.
2833

2934
### Code Generators
3035

app/controllers/create.js

Lines changed: 92 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ export default Ember.Controller.extend({
99

1010
charge: 12,
1111

12-
showLabels: true,
12+
radius: 5,
13+
14+
labels: true,
1315

1416
showNodeInfo: true,
1517

@@ -18,13 +20,13 @@ export default Ember.Controller.extend({
1820
nodes: [],
1921

2022
labelToggle: function () {
21-
if (this.get('showLabels')) {
23+
if (this.get('labels')) {
2224
this.send('showLabels', this.get('frame'), true);
2325
} else {
2426
this.send('removeLabels');
2527
}
2628

27-
}.observes('showLabels'),
29+
}.observes('labels'),
2830

2931
getNodes: function (frameType) {
3032
NProgress.start();
@@ -46,11 +48,11 @@ export default Ember.Controller.extend({
4648
// Create new node objects from the existing.
4749
rows.forEach(function (row, index) {
4850
if (index !== 0) {
49-
var nodeRef = that.get('nodes')
51+
var nodeObject = that.get('nodes')
5052
.findBy('id', row.id);
5153

5254
var node = {
53-
id: nodeRef.id,
55+
id: nodeObject.id,
5456
};
5557

5658
node[that.get('selectedColumn').get('id')] = row.value;
@@ -66,13 +68,14 @@ export default Ember.Controller.extend({
6668
// Use existing nodes data to create new nodes.
6769
rows.forEach(function (row, index) {
6870
if (index !== 0) {
69-
var nodeRef = that.get('nodes')
71+
var nodeObject = that.get('nodes')
7072
.findBy('id', row.id);
7173

7274
var node = {
73-
id: nodeRef.id,
74-
x: nodeRef.x,
75-
y: nodeRef.y
75+
id: nodeObject.id,
76+
x: nodeObject.x,
77+
y: nodeObject.y,
78+
fill: nodeObject.fill
7679
};
7780

7881
node[that.get('selectedColumn').get('id')] = row.value;
@@ -174,9 +177,9 @@ export default Ember.Controller.extend({
174177
actions: {
175178
loadPorject: function () {
176179
var that = this;
177-
180+
178181
var file = '/api/project/' + this.get('projectId');
179-
182+
180183
Ember.$.get(file, function () {
181184
that.send('importJSONData', file);
182185
that.send('hideModel', 'fileUpload');
@@ -242,7 +245,7 @@ export default Ember.Controller.extend({
242245
id: that.get('selectedColumn').get('id'),
243246
title: that.get('frameTitle'),
244247
foci: foci,
245-
radius: 5,
248+
radius: that.get('radius'),
246249
nodes: nodes,
247250
type: "Single Choice",
248251
switch: "On Click"
@@ -267,7 +270,7 @@ export default Ember.Controller.extend({
267270
id: that.get('selectedColumn').get('id'),
268271
title: that.get('frameTitle'),
269272
foci: foci,
270-
radius: 5,
273+
radius: that.get('radius'),
271274
nodes: nodes,
272275
type: "Multiple Choice",
273276
switch: "On Click"
@@ -289,7 +292,7 @@ export default Ember.Controller.extend({
289292
deleteFrame: function (frame) {
290293
this.get('store')
291294
.deleteRecord(frame);
292-
295+
293296
this.send('showNotification', 'error', 'Successfully deleted frame <b>' + frame.get('id') + '</b>.', true);
294297
},
295298

@@ -308,28 +311,28 @@ export default Ember.Controller.extend({
308311
fileUpload: function (file, resetInput) {
309312
if (file[0].type === "application/json") {
310313
var jsonFile = URL.createObjectURL(file[0]);
311-
314+
312315
this.send('importJSONData', jsonFile);
313-
316+
314317
this.send('hideModel', 'fileUpload');
315-
318+
316319
resetInput();
317320
} else if (file[0].type === "text/csv") {
318321
// Get local file path.
319322
var csvFile = URL.createObjectURL(file[0]);
320-
323+
321324
this.set('csvFile', csvFile);
322-
325+
323326
this.send('importCSVData', csvFile);
324-
327+
325328
this.send('hideModel', 'fileUpload');
326-
329+
327330
resetInput();
328331
} else {
329332
this.send('hideModel', 'fileUpload');
330-
333+
331334
this.send('showNotification', 'error', 'Invalid file type of uploaded file.', true);
332-
335+
333336
resetInput();
334337
}
335338
},
@@ -339,15 +342,23 @@ export default Ember.Controller.extend({
339342

340343
var that = this;
341344

345+
var first = true;
346+
342347
d3.json(file, function (frames) {
343348
frames.forEach(function (frameData) {
344349
// Create a new frame record.
345-
that.get('store')
350+
var frame = that.get('store')
346351
.createRecord('frame', frameData);
347352

353+
if (first) {
354+
that.send('selectFrame', frame);
355+
first = false;
356+
}
357+
348358
NProgress.inc();
349359
});
350360
NProgress.done();
361+
351362
that.send('showNotification', 'success', 'Project file successfully imported.', true);
352363
});
353364
},
@@ -588,9 +599,9 @@ export default Ember.Controller.extend({
588599
function drawNode(alpha) {
589600
return function (d) {
590601
var center = foci[d[frame.get('id')]];
591-
602+
592603
d.x += (center.x - d.x) * 0.09 * alpha;
593-
604+
594605
d.y += (center.y - d.y) * 0.09 * alpha;
595606
};
596607
}
@@ -616,12 +627,12 @@ export default Ember.Controller.extend({
616627
// Show labels and update nProgress.
617628
function end() {
618629
NProgress.inc();
619-
630+
620631
that.send('showNotification', 'success', 'Force layout completed, you can now modify it.', true);
621632

622633
that.set('frame', frame);
623634

624-
if (that.get('showLabels')) {
635+
if (that.get('labels')) {
625636
that.send('showLabels', frame, true);
626637
}
627638
}
@@ -644,7 +655,7 @@ export default Ember.Controller.extend({
644655

645656
removeLabels: function () {
646657
d3.select(".dotplot-nodes > svg")
647-
.selectAll('text.label')
658+
.selectAll('.label')
648659
.remove();
649660
},
650661

@@ -686,7 +697,9 @@ export default Ember.Controller.extend({
686697
// Update label coordinate value.
687698
d.labelx = minXNode.x + (fociWidth - this.getBBox().width) / 2;
688699

689-
return d.labelx;
700+
if (!_.isNaN(d.labelx)) {
701+
return d.labelx;
702+
}
690703
} else {
691704
return d.labelx;
692705
}
@@ -704,10 +717,21 @@ export default Ember.Controller.extend({
704717
// Update label coordinate value.
705718
d.labely = maxYNode.y + 25;
706719

707-
return d.labely;
720+
if (!_.isNaN(d.labely)) {
721+
return d.labely;
722+
}
708723
} else {
709724
return d.labely;
710725
}
726+
})
727+
.each(function (d) {
728+
// Remove if the option is not selected by anyone.
729+
if (_.isNaN(d.labelx) || _.isNaN(d.labely)) {
730+
this.remove();
731+
_.remove(frame.get('foci'), {
732+
id: d.id
733+
});
734+
}
711735
});
712736

713737
// Fade-in effect.
@@ -740,18 +764,18 @@ export default Ember.Controller.extend({
740764

741765
// Find the node (Frame Model) and update coordinate values.
742766
node.each(function (node) {
743-
var nodeRef = frame.get('nodes')
767+
var nodeObject = frame.get('nodes')
744768
.findBy('id', node.id);
745-
746-
nodeRef.x = node.x;
747-
748-
nodeRef.y = node.y;
769+
770+
nodeObject.x = node.x;
771+
772+
nodeObject.y = node.y;
749773
});
750774
},
751775

752776
changeGravity: function (event) {
753777
// Get slider value when the value changes.
754-
this.set('gravity', event.target.value);
778+
this.set('gravity', parseInt(event.target.value));
755779

756780
// Remove existing labels.
757781
this.send('removeLabels');
@@ -761,7 +785,7 @@ export default Ember.Controller.extend({
761785
},
762786

763787
changeCharge: function (event) {
764-
this.set('charge', event.target.value);
788+
this.set('charge', parseInt(event.target.value));
765789

766790
// Remove existing labels.
767791
this.send('removeLabels');
@@ -775,10 +799,14 @@ export default Ember.Controller.extend({
775799
var node = d3.select(".dotplot-nodes > svg")
776800
.selectAll('circle.node');
777801

802+
this.get('frame').set('radius', parseInt(event.target.value));
803+
804+
this.set('radius', parseInt(event.target.value));
805+
778806
// Transition into new radius value.
779807
node.transition()
780808
.duration(1000)
781-
.attr('r', event.target.value);
809+
.attr('r', parseInt(event.target.value));
782810
},
783811

784812
selectFrame: function (frame) {
@@ -816,25 +844,35 @@ export default Ember.Controller.extend({
816844

817845
// Check if it's a duplicate node.
818846
if (nodeId) {
819-
return that.get('frame')
847+
var mainNode = that.get('frame')
820848
.get('nodes')
821-
.findBy("id", nodeId).x;
849+
.findBy("id", nodeId);
850+
851+
if (mainNode) {
852+
return mainNode.x;
853+
} else {
854+
return that.get('width') / 2;
855+
}
822856
} else {
823-
return frame.get('nodes')
824-
.findBy("id", d.id).x;
857+
return that.get('width') / 2;
825858
}
826859
})
827860
.attr("cy", function (d) {
828861
var nodeId = d.id.substr(0, d.id.indexOf('--'));
829862

830863
// Check if it's a duplicate node.
831864
if (nodeId) {
832-
return that.get('frame')
865+
var mainNode = that.get('frame')
833866
.get('nodes')
834-
.findBy("id", nodeId).y;
867+
.findBy("id", nodeId);
868+
869+
if (mainNode) {
870+
return mainNode.y;
871+
} else {
872+
return that.get('height') / 2;
873+
}
835874
} else {
836-
return frame.get('nodes')
837-
.findBy("id", d.id).y;
875+
return that.get('height') / 2;
838876
}
839877
})
840878
.attr("r", frame.get('radius'))
@@ -852,16 +890,17 @@ export default Ember.Controller.extend({
852890
// Transition into the new node positions.
853891
node.transition().duration(1000)
854892
.style('opacity', 0.7)
893+
.attr("r", frame.get('radius'))
855894
.attr('cx', function (d) {
856895
return d.x;
857896
})
858897
.attr('cy', function (d) {
859898
return d.y;
860899
})
861900
.each("end", _.once(function () {
862-
if (that.get('showLabels')) {
901+
if (that.get('labels')) {
863902
NProgress.inc();
864-
that.send('showLabels', frame, true);
903+
that.send('showLabels', frame, false);
865904
} else {
866905
NProgress.done();
867906
}
@@ -928,7 +967,9 @@ export default Ember.Controller.extend({
928967
// Show notification on success.
929968
request.onreadystatechange = function () {
930969
if (request.readyState === 4 && request.status === 200) {
931-
that.send('showNotification', 'info', '<b>Project ID:</b> ' + request.responseText, false);
970+
var projectLink = 'http://localhost:4200/project?id=' + request.responseText;
971+
972+
that.send('showNotification', 'info', 'Success:<a target=_blank href=' + projectLink + '><b>' + request.responseText + '</b></a>', false);
932973
}
933974
};
934975

@@ -945,7 +986,7 @@ export default Ember.Controller.extend({
945986

946987
exportData: function (type) {
947988
var fileData = [];
948-
989+
949990
var that = this;
950991

951992
// Find all frame records.

0 commit comments

Comments
 (0)