Dc.js conflicts with Bootstrap styles on rowchart - javascript

I'm building a dashboard using dc.js/d3.js/crossfilter/bootstrap but I'm stuck on building a row chart.
The problem is that all the rows of the chart are rendering with the same length, even when the group is being calculated correctly and their values are distincts (4/3/1) (you can check it doing groupB.all() on terminal).
The source of the problem, which I found out after multiple headaches, is that bootstrap's styles overrides rect tags width. See the pictures where the problem goes away unchecking the width attribute on the .row>* selector's class.
I couldn't solve this. I tried writing styles to override it using width: revert, width: auto, width: initial and even tried using jQuery to remove that attribute after render, but cannot get it to work. It seems that none of these methods are exactly the same than unchecking the attribute definition on Chrome inspector.
I can't change any library version due it is a large project and has other dashboards already built with this same stack.
Here is the jsfiddle with the exact same scenario.

I am afraid that a workaround is only available in a recent version of the library.
If you can't update the version of the dc.js library you are using, you could try removing the conflicting class and provide a different one instead.
For example, taking as reference your fiddle, please, try the following:
const data = [
{author: "email1", otherField: "asd1"},
{author: "email1", otherField: "asd2"},
{author: "email2", otherField: "asd3"},
{author: "email1", otherField: "asd4"},
{author: "email3", otherField: "asd5"},
{author: "email3", otherField: "asd6"},
{author: "email3", otherField: "asd7"},
{author: "email3", otherField: "asd8"},
]
var ndx = crossfilter(data)
var dimAuthor = ndx.dimension(function(d){ return d.author })
var groupB = dimAuthor.group().reduceCount()
var chartB = new dc.RowChart("#chart-b");
chartB
.height(500)
.width(600)
.margins({top: 20, right: 50, bottom: 10, left: 45})
.dimension(dimAuthor)
.group(groupB)
.label(function (d){
return `${d.key} (${d.value})`;
})
.ordering(function(d){ return -d.value; })
.x(d3.scaleLinear().domain([6,500]))
.xAxis(d3.axisTop())
.elasticX(true)
dc.renderAll();
// Remove the 'row' class and use for example 'dc-row' instead
d3.selectAll(".dc-chart g.row")
.classed("row", false)
.classed("dc-row", true);
As you can notice, I copied and pasted the whole javascript fragment you. published, but these lines are the only necessary:
d3.selectAll(".dc-chart g.row")
.classed("row", false)
.classed("dc-row", true);
You probably still will need to tweak the chart styles but at least they will have the right width. For example, consider including the following:
.dc-chart g.dc-row rect {
fill-opacity: .8;
cursor: pointer;
}

Related

Can't swap images in a ngx-gallery

I'm having a little issue using ngx-gallery Here is the github page and my stackblitz example.
Scenario - I want my user click a button to swap the images around to the first image in the gallery.
Ex. User clicks button and moves the image from position 3 to image position 1. Including the small thumbnail, the medium image (main viewer) and the big preview image.
Problem - Everything I've tried doesn't seem to work. I can't really find any methods that swap the indexes and when I swap them manually nothing happens.
FYI - I can add and delete images to the viewer with push and pop, I just can't set (swap) the first image programmatically with another.
stackblitz example
Here is some of the examples I've tried.
export class AppComponent implements OnInit {
#ViewChild('gallery') gallery: NgxGalleryComponent;
galleryOptions: NgxGalleryOptions[];
galleryImages: NgxGalleryImage[];
constructor() {}
ngOnInit() {
this.galleryOptions = [{
width: '600px',
height: '400px',
thumbnailsColumns: 4,
arrowPrevIcon: 'fa fa-chevron-left',
arrowNextIcon: 'fa fa-chevron-right',
imageAnimation: NgxGalleryAnimation.Slide
}
];
this.galleryImages = [{
small: 'https://preview.ibb.co/jrsA6R/img12.jpg',
medium: 'https://preview.ibb.co/jrsA6R/img12.jpg',
big: 'https://preview.ibb.co/jrsA6R/img12.jpg'
},
{
small: 'https://preview.ibb.co/kPE1D6/clouds.jpg',
medium: 'https://preview.ibb.co/kPE1D6/clouds.jpg',
big: 'https://preview.ibb.co/kPE1D6/clouds.jpg'
},
{
small: 'https://preview.ibb.co/mwsA6R/img7.jpg',
medium: 'https://preview.ibb.co/mwsA6R/img7.jpg',
big: 'https://preview.ibb.co/mwsA6R/img7.jpg'
}, {
small: 'https://preview.ibb.co/kZGsLm/img8.jpg',
medium: 'https://preview.ibb.co/kZGsLm/img8.jpg',
big: 'https://preview.ibb.co/kZGsLm/img8.jpg'
},
];
}
swap() {
console.log("button clicked!");
// doesn't do anything
[this.galleryImages[2], this.galleryImages[0]] = [this.galleryImages[0], this.galleryImages[2]];
// doesn't do anything
[this.gallery.thumbnails.images[2], this.gallery.thumbnails.images[0]] = [this.gallery.thumbnails.images[0], this.gallery.thumbnails.images[2]];
// doesn't do anything
[this.gallery.images[2], this.gallery.images[0]] = [this.gallery.images[0], this.gallery.images[2]];
}
}
<div class="gallery-wrapper">
<ngx-gallery #gallery [options]="galleryOptions" [images]="galleryImages" class="ngx-gallery"></ngx-gallery>
</div>
<button (click)="swap()">swap image 1 and 3</button>
This may be because you are mutating the array. Sometimes Angular change detection only kicks in when you do not mutate.
Mutating happens when you change the array (the items in the array or the order of items in the array) but do not change the array reference.
To avoid mutating try:
this.galleryImages = [this.galleryImages[2], this.galleryImages[1], this.galleryImages[0]]
Alternatively, even when you do mutate an Array you can solve the problem by running lodash cloneDeep afterwards, which will get you a new reference after mutating:
import { cloneDeep } from 'lodash-es'
// your existing code
this.galleryImages = cloneDeep(this.galleryImages)
Note that there are some decent npm packages for changing the position of items in an array such as array-move - this avoids mutation - note there are other good packages for this too, look for competitors on npm trends

Label to flows in JointJS

I'm working with jointJs and Rappid. I know how to draw a bpmn diagram, as the photo I have attached. I'm drawing the elements, but I'm having some problems with rows (flows). Is there any way to add a flow label or name? As I added on my image in red color.
I have seen this in their documentation, but I can't see anything about labels
var flow = new joint.shapes.bpmn.Flow({
source: { id: task.id },
target: { id: annotation.id },
flowType: 'association'
});
Thanks,
You may want to look into dia.Link.prototype.labels, since BPMN Flows are just Links extensions (joint.shapes.bpmn.Flow = joint.dia.Link.extend({).
An example to your flow:
flow.label(0, // the label's index (you can have multiple labels per link/flow)
{
position: .5, // place it halfway on the link (0-1)
attrs: {
text: { fill: 'red', text: 'Label' }
}
}
);

Set Container Element of a jsPlumb Line

I have two small green divs within my canvas. It can be drag within the canvas with an id myid_templates_editor_canvas, with the use of the code below:
myid_templates_editor_make_draggable('div1');
myid_templates_editor_make_draggable('div2');
// Make an element draggable within the canvas
function myid_templates_editor_make_draggable(id){
jQuery('#' + id).draggable({
cursor: 'move',
cursorAt: { top: 56, left: 56 },
containment: '#myid_templates_editor_canvas',
});
}
See images below:
I have made a line between 2 draggable divs using jsPlumb.
var jsPlumb_instance = jsPlumb.getInstance();
var endpointOptions = {
anchor:'BottomCenter',
maxConnections:1,
endpoint:['Rectangle',{width:'0px', height:'0px' }],
paintStyle:{fillStyle:'black'},
connectorStyle : { lineWidth: '1px' , strokeStyle: 'black' },
connector : ['Straight'],
setDragAllowedWhenFull:true,
};
div1Endpoint = jsPlumb_instance.addEndpoint('div1', endpointOptions);
div2Endpoint = jsPlumb_instance.addEndpoint('div2', endpointOptions);
jsPlumb_instance.connect({
source:div1Endpoint,
target:div2Endpoint,
});
jsPlumb_instance.draggable('div1');
jsPlumb_instance.draggable('div2');
I dont want the line outside the canvas border. See 3rd picture.
I want the line to be contained within the canvas with an id myid_templates_editor_canvas.See the image below:
I tried changing part of the code above with the the code below, with no luck.
jsPlumb_instance[id].draggable(id1, {containment:'#myid_templates_editor_canvas'});
jsPlumb_instance[id].draggable(id2 , {containment:'#myid_templates_editor_canvas'});
Yes, the two points was somehow constrained because the length of the maximum line was limited but still goes out of the border of the canvas.Below is the html set-up of the canvas and two points.
<table>
<tr>
<td>
<canvas id="myid_templates_editor_canvas"></canvas>
<div id="div1"></div>
<div id="div2"></div>
</td>
</tr>
</table>
I worked with jsPlumb for quite long already and I remembered it need to refer to a lot of library.
Because jsPlumb using draggable feature from jQuery UI, you can read this article for understanding how it is being worked.
https://jqueryui.com/draggable/#constrain-movement
In your case, myid_templates_editor_canvas will not be consider as the containment, it is for drawing only. So I suggest you to modify your html as below try, let me know your result as well.
I put an ID for table element and it will be the containment for 2 end points. The containment must be an element that contains child element - in the other words - parent element.
myid_templates_editor_make_draggable('div1');
myid_templates_editor_make_draggable('div2');
// Make an element draggable within the canvas
function myid_templates_editor_make_draggable(id){
jQuery('#' + id).draggable({
cursor: 'move',
cursorAt: { top: 56, left: 56 },
containment: '#main-container',
});
}
<table id="main-container">
<tr>
<td>
<canvas id="myid_templates_editor_canvas"></canvas>
<div id="div1"></div>
<div id="div2"></div>
</td>
</tr>
</table>
Actually you can set containment via jsPlumb. See my jsFiddle. The reason why your solution did not work is that you have set draggable via jsPlumb, not jQuery. They do not know about it other, so can not work together. You need to provide options to draggable function:
jsPlumb_instance.draggable(element, { containment:true });
To know more about draggable in jsPlumb see help. You can set containment container explicitly when you get instance of jsPlumb:
var jsPlumb_instance = jsPlumb.getInstance({ Container:"inner" });
You can also specify DragOptions and DropOptions if you need (more info).
It is better to set draggable via jsPlumb, as a plus, then no need to call repaint after dragging is finished. A huge performance benefit with a lot of elements.
A common feature of interfaces using jsPlumb is that the elements are
draggable. You should use the draggable method on a jsPlumbInstance to
configure this:
myInstanceOfJsPlumb.draggable("elementId");
...because if you don't, jsPlumb won't know that an element has been
dragged, and it won't repaint the element.
I had made a solution to my problem. I changed my code above to to code below:
myid_templates_editor_make_draggable('div1');
myid_templates_editor_make_draggable('div2');
//Make an element draggable within the canvas
function myid_templates_editor_make_draggable(id){
jQuery('#' + id).draggable({
cursor: 'move',
cursorAt: { top: 56, left: 56 },
containment: '#myid_templates_editor_canvas',
drag: function(e, ui){
jsPlumb_instance.repaintEverything();
},
});
}
I had also omit the line of code that make JsPlumb two endpoints draggable.
var jsPlumb_instance = jsPlumb.getInstance();
var endpointOptions = {
anchor:'BottomCenter',
maxConnections:1,
endpoint:['Rectangle',{width:'0px', height:'0px' }],
paintStyle:{fillStyle:'black'},
connectorStyle : { lineWidth: '1px' , strokeStyle: 'black' },
connector : ['Straight'],
setDragAllowedWhenFull:true,
};
div1Endpoint = jsPlumb_instance.addEndpoint('div1', endpointOptions);
div2Endpoint = jsPlumb_instance.addEndpoint('div2', endpointOptions);
jsPlumb_instance.connect({
source:div1Endpoint,
target:div2Endpoint,
});
Hope it helps everyone that is going through the same problem with me.

dc-js line chart showing extra filled line at average change

I am using the library dc-js to display a line chart. As far as I can tell, everything is working well. The chart even mostly displays correctly. However, in addition to the line I want on the chart, there is a black line that sits behind the blue one, that is filled black. The black line is a single linear increase from the first value to the last value.
Here's my code:
var stripeData = <Data>;
var mrrLineChart = dc.lineChart("#line-chart");
var data = [];
// console.log(stripeData);
stripeData.forEach(function (dat) {
// console.log(dat.created);
data.push({date: parseDate(dat.created.substr(0, 10)), amount: dat.amount});
});
// console.log(data);
var ndx = crossfilter(data);
var dateDim = ndx.dimension(function(d) {
return d.date;
});
var amount = dateDim.group().reduceSum(function(d) { return +d.amount; });
// console.log(amount);
var minDate = dateDim.bottom(1)[0].date;
var maxDate = dateDim.top(1)[0].date;
// console.log(minDate);
// console.log(maxDate);
mrrLineChart.width(960)
.height(150)
.margins({top: 10, right: 50, bottom: 50, left: 50})
.dimension(dateDim)
.group(amount, "Amount")
.transitionDuration(500)
.brushOn(false)
.renderArea(true)
.renderDataPoints(true)
.title(function(d){
return (d.key.getMonth()+1) + "/" + d.key.getDate() + "/" + d.key.getFullYear() + "\nAmount: $" + d.value.toFixed(2);
})
.elasticY(true)
.x(d3.time.scale().domain([minDate,maxDate]))
.xAxisLabel("Date")
.yAxisLabel("Revenue")
.render()
;
The idea is to group the transactions by day, and sum up the revenue per day.
This looks like a CSS problem. A bit hard to tell without the HTML and CSS posted, but at a guess, you should add:
fill: none;
to one of the CSS classes that you're using in your SVG elements. The dc.css file that comes with the dc.js distribution would normally take care of that, but perhaps it's been edited.
Even though it seems logic to apply fill:none in the dc.css it did not work for me. The initial solution was:
.on('renderlet', function (chart) {
d3.selectAll('.line')
.style('fill', 'none')
But then it rendered first with the fill (inside componentDidMount,React).Than I settled for putting the style in the index.html page as instructed here https://bl.ocks.org/mbostock/1166403 :
<style>
path.line {
fill: none;
stroke: green;
stroke-width: 1.5px;
}
</style>
This one works just fine,but still interested in applying the style inside the css and not taking the style into the html.

Reusing SVG.js code for various SVG's

I'm getting to grips with SVG.js
I have a pattern effect that I've created and would like to use in a number of SVG's.
I can create it in one SVG with the following code...
$( document ).ready(function() {
var draw = SVG('geo').size(1200, 1700);
// 100 lines of js creating geometric pattern, effectively this...
var rect = draw.polygon(coordinates).fill('#fff').stroke({ width: 1, color:'#fff'}).opacity(0)
});
This creates an SVG with ID geo. But I'd like to use this code again to generate various SVG's, ideally with different options (colour etc).
SVG('geo') refers to a particular SVG, how do I make it so I can apply this to any SVG I want on the page?
Hope that made sense
You can define a function that does this repeatedly. Something like the following:
function create_svg(dom_id, width, height, coord) {
var draw = SVG(dom_id).size(width, height);
var rect = draw.polygon(coord)
.fill('#fff')
.stroke({
width: 1,
color: '#fff'
})
.opacity(0);
}
$(function() {
create_svg('geo', 1200, 1700, coordinates);
create_svg('geo2', 1000, 1500, other_coordinates);
)};
If you need to use the created SVGs further, later on in the code, you could make the create_svg function return the created SVG object to a variable in your document.ready function.

Categories

Resources