Cannot access variables in angular from d3 Funnel js callback - javascript

As per the latest document in D3 JS funnel I have click event callback as referred by the documentation. But when I'm unable to access functions from inside angular component using this.try().
Here is the implementation, don't know how to implement it.
JS Code
const options = {
chart: { bottomPinch: 1, animate: 200, height: 300 },
block: {
// dynamicHeight: true,
// dynamicSlope: true,
highlight: true,
},
events: {
click: {
block(d) {
console.log(d.label.raw);
this.try(d.label.raw);
},
},
},
tooltip: { enabled: true, }
};
const chart = new D3Funnel('#d3Funnel');
chart.draw(data, options);
})
HTML
<div id="d3Funnel"></div>
It gives the error
ERROR TypeError: this.try is not a function
at SVGPathElement.block
I don't know how to resolve this.
Reference of library
https://github.com/jakezatecky/d3-funnel

block(d) { ... } is just a shorthand for block: function(d) { ... }, which would not lexically bind this.
If you replaced your event with an arrow function, such as block: (d) => { ... }, your code would be able to resolve this as you intend.

Related

How to pass a function to component to handle a drag event

I want to use v-for and is to render the components I need. So I create the component Cube.vue like this:
<script>
export default {
name: 'cube',
render: function(createElement) {
return createElement("div",{
props: {
style: {
type: Object
},
dragstartHandler: {
type: Function
},
classNames: {
type: Array|String|Object
}
},
style: this.style,
attrs: {
draggable: "true",
},
on: {
dragstart: this.dragstartHandler
},
'class': this.classNames
},[
createElement("div",{
class: ["resizer", "top-left"]
}),
createElement("div",{
class: ["resizer", "top-right"]
}),
createElement("div",{
class: ["resizer", "bottom-left"]
}),
createElement("div",{
class: ["resizer", "bottom-right"]
}),
])
}
}
</script>
And then, I use it like this
<component
v-for="component in components"
:class="component.classes"
:key="component.refValue"
:is="component.type"
:style="component.style"
:dragstartHandler="component.dragstartHandler"
:ref="component.refValue"
>
</component>
Everything as I expected, except the dragstartHandler. It throws an error
[Vue warn]: Invalid handler for event "dragstart": got undefined
I try to console.log() the components. The result is :
[{…}, __ob__: Observer]
0:
classes: Array(2)
dragstartHandler: ƒ ()
refValue: "cube-0"
style: Object
type: "cube"
It really is a function. But I don't know why it go to undefined in the render. I have checked I didn't spell wrong.
I just want pass the function to the component to handle the drag event. So how does it happened and what should I do to resolve it.
The dragHandler function is these:
dragstartCopyHandler(event) {
event.dataTransfer.setData("elementId", event.target.id);
event.dataTransfer.setData("componentOffsetX", event.offsetX);
event.dataTransfer.setData("componnetOffsetY", event.offsetY);
event.dataTransfer.setData("dropEffect", "copy");
event.dataTransfer.dropEffect = "copy";
},
dragstartMoveHandler(event) {
console.log("move start")
event.dataTransfer.setData("elementId", event.target.id);
event.dataTransfer.setData("componentOffsetX", event.offsetX);
event.dataTransfer.setData("componnetOffsetY", event.offsetY);
event.dataTransfer.setData("dropEffect", "move");
event.dataTransfer.dropEffect = "move";
},
And I pass the dragstartMoveHandler to the component.
this.components.push({
refValue: `${elementId}-${this.count}`,
type: elementId,
style: style,
dragstartHandler: this.dragstartMoveHandler,
classes: ["component", elementId]
});
I write the pages use js to control Dom before. And today I want to rewrite it with vue. So here might something wrong with the function, but the problem now is the function passed is undefined.
The cube component needs to define a prop for dragstartHandler so that it receives it from the parent for passing it on to the div. The same is true of the style and class bindings, which are also not working as you expect, but you don't see an error there because those are built-in bindings which get transferred to the root element.
Cube.vue
render() {
...
},
props: {
dragstartHandler: {
type: Function,
},
}

Prevent click event in angular nvD3 Stacked Area Chart

I'm trying to prevent the default behavior when I click on the angular-nvD3 Stacked Area Chart. I managed to access the onclick function, but I don't know how to prevent the event (modifies the graphic) from happening. I don't want the graphic to change when the user clicks on it.
.js:
$scope.stackedAreaChartOptions = {
chart: {
type: 'stackedAreaChart',
height: 450,
margin : {
top: 20,
right: 20,
bottom: 30,
left: 40
},
x: function(d){return d[0];},
y: function(d){return d[1];},
useVoronoi: false,
clipEdge: true,
duration: 100,
useInteractiveGuideline: true,
xAxis: {
showMaxMin: false,
tickFormat: function(d) {
return d3.time.format('%H:%M')(new Date(d))
}
},
yAxis: {
tickFormat: function(d){
return d3.format(',.2f')(d);
}
},
zoom: {
enabled: false,
scaleExtent: [1, 10],
useFixedDomain: false,
useNiceScale: false,
horizontalOff: false,
verticalOff: true,
unzoomEventType: 'dblclick.zoom'
},
//chart events
stacked: {
dispatch: {
areaClick:
function (t,u){ null; console.log("areaClick");}
,
areaMouseover:
function (t,u){ null; console.log("areaMouseover");}
,
areaMouseout:
function (t,u){null; console.log("areaMouseout");}
,
renderEnd:
function (t,u){null; console.log("renderEnd");}
,
elementClick:
function (t,u){null; console.log("elementClick");}
,
elementMouseover:
function (t,u){null; console.log("elementMouseover");}
,
elementMouseout:
function (t,u){ null;console.log("elementMouseout");}
}
},
controlLabels: {stacked:"Absoluto", expanded:"Relativo"},
controlOptions:
[
"Stacked",
false,
"Expanded"
]
},
title: {
enable: true,
text: '',
css: {
'font-weight': 'bold'
}
},
caption: {
enable: true,
html: 'Visualización por horas de acceso a noticia',
css: {
'text-align': 'center',
'margin': '2px 13px 0px 7px',
'font-style': 'italic'
}
}
};
HTML:
<nvd3 options="stackedAreaChartOptions" data="stackedAreaChartData" api="api"></nvd3>
When I click on the graphic, the messages (console.log) are being shown, but I need to prevent the click event from happening.
I know this is an old question, but I run into this problem for my project and here is how I solved it.
It seems it's not possible to disabled these events using angular-nvd3. You must disable them using NVD3.
Get the chart api object available on your angular-nvd3 chart and disable the events on the chart object binded to this api:
HTML
<nvd3 options="options" data="data" api="chartAPI"></nvd3>
Javascript
$timeout( function() {
if ($scope.chartAPI) {
var chart = $scope.chartAPI.getScope().chart;
chart.stacked.dispatch.on('areaClick.toggle', null);
chart.stacked.dispatch.on('areaClick', null);
}
}, 1000);
I made a timeout be sure to have the chartAPI when doing the changes.
Note : It seems you have to disable these events again when you update or refresh the chart (chart.refresh()).
Working example here: https://codepen.io/mvidailhet/pen/JNYJwx
It seems there is a glitch in the chart update on Codepen, but you get the point :)
Hope it helps!
You were close. CSS pointer-events:none; has the disadvantage that it turns off every pointer event (most importantly hover, mouseenter and mouseout).
So IMHO you should avoid to use it.
Actually you were close. You should not pass an it-does-nothing function but null or undefined instead to options.chart.stacked.dispatch.areaClick. Like this:
//chart events
stacked: {
dispatch: {
areaClick: void 0
}
}
I had this very same problem and spent more than an hour to find it out.
EDIT
Turned out that I was wrong. It solved just because it ran into an error that prevented the event. So you can throw an error and everything is fine... :)
Also found a workaround but that causes memory leak, so I'll not share that.
My solution was: accept that it applies click event and hides all other layers. Too small issue to invest more time and effort in it.

Highlight Single Bar/Column in Highcharts on load

I have an existing highchart on which I need to highlight a single column.
It is a percentile graph that has been around for a while, I am still pretty new to high charts, but I have seen a similar question here on SO, this question, though deals with stacked bars and a click event...
The code makes sense to me in the example, but I guess I am missing something,
Here is my sample (trying to highlight the 24th column)
https://jsfiddle.net/52t43y3k/2/
Here is the question I saw:
Highlight one bar in a series in highcharts?
for ref, my code is
var col_chart = $('#section-2-chart').highcharts({
chart: {
type: 'column'
},
tooltip: { enabled: false },
credits:false,
title: false,
xAxis: {
title:{text:'PERCENTILES'},
type: 'Percentile',
labels: {
enabled:true,
formatter: function() {
return this.value*2;
}
}
},
yAxis: {
min: 0,
title:{text:'Total Image Weight'}
},
legend: {
enabled: false
},
series: [{
data: [169,12003,38308.5,61739.7,97069,131895.5,161086.7,198758.7,219779.3,243567.7,276607.7,296931.5,327457.5,362840.3,383978,410685.5,443774,467039.5,491654,517205,544754.7,578468.3,605392.5,644214.5,693765,766953.7,806616,855380.7,894161,942282,1001179.7,1062697.7,1125773.3,1186437,1236893.7,1314379.5,1378944,1454090.3,1553065,1689346,1833150,1957396,2077851.5,2228644.7,2390102,2725365.5,3147844.3,3607372,4239281.5,5190061,9422370.8],
tooltip: {
pointFormat: '<b>{point.y:f} Bytes</b>'
}
}]
});
//TRIED THIS AND series.data[24] - essentially the 24th bar should be highlighted
col_chart.series[0].data[24].update({color:'red'});
You need to access the highcharts off of your jquery object:
col_chart.highcharts().series[0].data[24].update({
color: 'red'
});
For clarity
In your example, the following is true:
console.log(col_chart instanceof jQuery); // true
From the highcharts source:
/**
* Register Highcharts as a plugin in jQuery
*/
if (win.jQuery) {
win.jQuery.fn.highcharts = function () {
var args = [].slice.call(arguments);
if (this[0]) { // this[0] is the renderTo div
// Create the chart
if (args[0]) {
new Highcharts[ // eslint-disable-line no-new
isString(args[0]) ? args.shift() : 'Chart' // Constructor defaults to Chart
](this[0], args[0], args[1]);
return this;
}
// When called without parameters or with the return argument, return an existing chart
return charts[attr(this[0], 'data-highcharts-chart')];
}
};
}
Meaning, highcharts() is a plugin for jQuery, so you can access it (assuming it's been attached to the dom element already, as in your case above) by calling highcharts off a jQuery selector instance.

Setting properties of FlowPlayer dynamically

I'm using Flow Player in ASP.NET Web Forms (VS 2010) and want to set some of its properties, like autoPlay, dynamically (read from a config file). But autoPlay don’t seem to be set dynamically. For example, the following code with autoPlay set to true (or false) works correctly:
function initialize() {
player = flowplayer("flowPlayer", "<%=HttpType %>://releases.flowplayer.org/swf/flowplayer.commercial-3.2.15.swf", {
key: '#$b9299630d834a59dcb9',
clip: {
autoPlay: true,
autoBuffering: true,
scaling: 'fit',
onFinish: function () {
}
},
canvas: {
// configure background properties
background: '#000000',
// remove default canvas gradient
backgroundGradient: 'none'
}
});
}
However, obtaining the value AutoPlay from code-behind (which would obtain a value from a config file) doesn’t work. Is there a better way to set the value dynamically? I can’t find online documentation that addresses setting these value dynamically:
function initialize() {
player = flowplayer("flowPlayer", "<%=HttpType %>://releases.flowplayer.org/swf/flowplayer.commercial-3.2.15.swf", {
key: '#$b9299630d834a59dcb9',
clip: {
autoPlay: <%=AutoPlay%>,
autoBuffering: true,
scaling: 'fit',
onFinish: function () {
}
},
canvas: {
// configure background properties
background: '#000000',
// remove default canvas gradient
backgroundGradient: 'none'
}
});
}
Thanks!
<body/>
<div id="player" class="fixed-controls"></div>
HTML
<script>
$(function() { // make sure the DOM is ready
$("#player").flowplayer({
ratio: 5/12,
rtmp: "rtmp://s3b78u0kbtx79q.cloudfront.net/cfx/st",
playlist: [
[
{ webm: "http://stream.flowplayer.org/bauhaus.webm" },
{ mp4: "http://stream.flowplayer.org/bauhaus.mp4" },
{ flash: "mp4:bauhaus" }
]
]
}).one('ready', function(ev, api) {
api.resume();
});
});

Why is YUI test console ignored when test is used by two YUI instances

If I run a test case like this, my test results show up inside the YUI test-console widget:
YUI({debug: true}).use('test', 'event-base', 'test-console', function (Y) {
fooTests = new Y.Test.Case({
name: "foo",
testFoo: function () {
Y.assert(5 == 6);
}
});
Y.on("domready", function () {
(new Y.Test.Console({
newestOnTop: false,
style: 'block'
})).render('#log');
Y.Test.Runner.add(fooTests);
Y.Test.Runner.run();
});
});
If I run the exact same code but create another YUI instance that uses 'test' first, the tests show up in the browser javascript console (if it's open).
YUI({debug: true}).use('test', function (Y) {
});
YUI({debug: true}).use('test', 'event-base', 'test-console', function (Y) {
fooTests = new Y.Test.Case({
name: "foo",
testFoo: function () {
Y.assert(5 == 6);
}
});
Y.on("domready", function () {
(new Y.Test.Console({
newestOnTop: false,
style: 'block'
})).render('#log');
Y.Test.Runner.add(fooTests);
Y.Test.Runner.run();
});
});
Is there a way to get the results to show up in the test-console widget when 'test' is used by another YUI instance?
I found the answer here.
I had to add
logSource: Y.Global
To Test.Console's parameter object.
(new Y.Test.Console({
logSource: Y.Global,
newestOnTop: false,
style: 'block'
})).render('#log');

Categories

Resources