is there a angularJS directive for heatmap.js?
Can't find anything and can't get it to work
Thanks
= Edit =
I get this error whether I used my code or the one below (both work). My problem was actually the version of the heatmap.js that that I was using from the bower. When I download the min.js used in the fiddle it all works fine.
TypeError: Cannot read property 'style' of null
at Object.heatmap.resize (http://localhost:56080/app/bower_components/heatmap.js/src/heatmap.js:363:74)
at Object.heatmap.init (http://localhost:56080/app/bower_components/heatmap.js/src/heatmap.js:386:20)
at Object.heatmap (http://localhost:56080/app/bower_components/heatmap.js/src/heatmap.js:331:14)
at Object.heatmapFactory.create (http://localhost:56080/app/bower_components/heatmap.js/src/heatmap.js:627:24)
at link (http://localhost:56080/app/js/directives/MainDirective.js:9:36)
Simple wrapper directive for heatmap.js
HTML
<div ng-app="myapp">
<div ng-controller="MyCtrl1">
<heat-map data="passed_data"></heat-map>
</div>
</div>
JS
var myApp = angular.module('myapp',[]);
myApp
.controller('MyCtrl1', function ($scope) {
// now generate some random data
var points = [];
var max = 0;
var width = 840;
var height = 400;
var len = 200;
while (len--) {
var val = Math.floor(Math.random()*100);
max = Math.max(max, val);
var point = {
x: Math.floor(Math.random()*width),
y: Math.floor(Math.random()*height),
value: val
};
points.push(point);
}
// heatmap data format
$scope.passed_data = {
max: max,
data: points
};
})
.directive('heatMap', function(){
return {
restrict: 'E',
scope: {
data: '='
},
template: '<div container></div>',
link: function(scope, ele, attr){
scope.heatmapInstance = h337.create({
container: ele.find('div')[0]
});
scope.heatmapInstance.setData(scope.data);
}
};
});
CSS
heat-map {
width: 840px;
height: 400px;
display: block;
}
heat-map div {
height: 100%;
}
JsFiddle - http://jsfiddle.net/jigardafda/utjjatuo/2/
heatmap.js example reference link
http://www.patrick-wied.at/static/heatmapjs/example-minimal-config.html
jad-panda's answer (https://stackoverflow.com/a/30193896/3437606) is really helpfull.
But if you don't want to make the size of the heatmap hardcoded in css and apply them dynamicaly with ng-style, you have to make the following minor changes.
HTML
<div ng-style="heatMapStyle">
<heat-map data="passed_data"></heat-map>
</div>
Controller
just add the style object to the $scope like
$scope.heatMapStyle = {
"height": 100+ "px",
"width": 150+ "px"
};
The rest of the controler is the same as in jad-panda's answer.
Directive
.directive('heatMap', ['$timeout', function ($timeout) {
return {
restrict: 'E',
scope: {
data: '='
},
template: '<div container></div>',
link: function (scope, ele, attr) {
function init() {
scope.heatmapInstance = h337.create({
container: ele.find('div')[0]
});
scope.heatmapInstance.setData(scope.data);
}
//to ensure that the wrapping style is already applied
$timeout(init,0);
}
};
}])
The $timout is essential to ensure that the heatmap is initialized in the next digestcycle of AngularJs when the ng-styleis already applied.
CSS
And last the new CSS:
heat-map {
position: relative;
width: 100%;
height: 100%;
}
heat-map div {
height: 100%;
}
Just found an oficial wrapper for heatmap.js, hosted in the same github repository.
It can be downloaded from: https://github.com/pa7/heatmap.js/blob/master/plugins/angular-heatmap/angular-heatmap.js
And it's explained here:
https://www.patrick-wied.at/static/heatmapjs/plugin-angular-heatmap.html
Related
I am trying to use $sce.trustAsResourceUrl to sanitize a Twitter URL that I am generating on the controller, however the button that is produced ignores the URL, and uses the current page URL instead.
If I try printing what is in the controller to screen, that works fine.
<iframe id="twitter-widget-0" scrolling="no" frameborder="0" allowtransparency="true" class="twitter-share-button twitter-share-button-rendered twitter-tweet-button" title="Twitter Tweet Button" ng-src="{{ctrl.twitterUniqueURL}}" style="position: static; visibility: visible; width: 60px; height: 20px;"></iframe>
.directive('referral', function ($rootScope, $sce, $interval, regex) {
return {
restrict: 'E',
replace: true,
templateUrl: $sce.trustAsResourceUrl($rootScope.environment.resources + 'website/html/manage/my-stuff/referral.html'),
scope: true,
link: function (scope) {
scope.ctrl = {
init: function() {
scope.ctrl.getReferralCode();
},
form: {
email: ''
},
twitterUniqueURL: null,
getReferralCode: function() {
var check = $interval(function() {
if ($rootScope.ctrl && $rootScope.ctrl.data &&
$rootScope.ctrl.data.customer) {
scope.ctrl.referralCode =
$rootScope.ctrl.data.customer.referralCodeForCustomer;
scope.ctrl.twitterUniqueURL = $sce.trustAsResourceUrl("https://platform.twitter.com/widgets/tweet_button.b813cd3227574096a07e094b73331535.en.html#dnt=false&id=twitter-widget-0&lang=en&original_referer=https%3A%2F%2Fexample.co.uk%2Faccount%2F%3Freferral%26Code%3D" + scope.ctrl.referralCode + "&size=m&text=Receive%20%C2%A310%20when%20signing%20up%20for%20example.%20Live%20a%20Bigger%20Life%2C%20One%20Box%20at%20a%20Time.&time=1528123666174&type=share&url=https%3A%2F%2Fexample.co.uk%2F%3FReferral%3D" + scope.ctrl.referralCode + "&via=exampleUK");
}
}, 300)
},
};
scope.ctrl.init();
}
};
})
Any ideas?
Apologies if I haven't explained this very well - only started using AngularJS two weeks ago.
Thanks
James
I would like to have image preview upload with trigger another element,
so that I have put together in directives.
https://stackoverflow.com/a/25674293
AngularJS Image Preview before Upload showing previous image selected
it is so confusing to me.
How can I make directives image preview uploading by clicking image?
I try it put together but it fails,
https://jsfiddle.net/tictac18g/83m659zL/4/
.directive('fileButton', function ($parse) {
return {
restrict: 'AE',
link: function (scope, element, attrs) {
scope.setimage = function () {
var file = scope.myFile;
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
scope.$apply(function () {
scope.ImageSrc = e.target.result;
})
}
}
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function (e) {
scope.$apply(function (e) {
modelSetter(scope, element[0].files[0]);
});
scope.setimage();
});
},
compile: function (element) {
var fileInput = angular.element('<input type="file" file-model="myFile" multiple />')
fileInput.css({
position: 'absolute',
top: 0,
left: 0,
'z-index': '2',
width: '100%',
height: '100%',
opacity: '0',
cursor: 'pointer'
});
element.append(fileInput)
return this.link;
}
}
})
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-init="ImageSrc ='https://www.google.com/images/srpr/logo3w.png'" file-button>
<img width="200" ng-src="{{ImageSrc}}" />
</div>
</div>
Thanks in advance.
update:
I have put two separate directives, it seems work, however I can't can't figure out to make one directive.
here is my result, https://jsfiddle.net/tictac18g/4y0seej9/
but the result doesn't match what I'm looking for, because the size of uploaded image couldn't be restraint.
and it doesn't quite the same result as the jquery, http://jsfiddle.net/rodolphobrock/q8f33f8L/
would you give me some advise, it can't be achieve the same features in angularjs?
update 2:
I can't get it work with native directives, so I have applied it with JQuery plugins.
my result is that.
https://fiddle.jshell.net/tictac18g/83m659zL/
I have several elements in a container. One of the rows has two icons in it: zoom in and zoom out. When you click Zoom In, I'd like all the row's widths to grow.
<div id="events">
<year>year 1</year>
<year>year 2</year>
<year>year 3</year>
<year>year 4</year>
<div id="scaling">
<md-icon aria-label="Zoom In" class="material-icons" ng-click="zoomIn()">zoom_in</md-icon>
<md-icon aria-label="Zoom Out" class="material-icons" ng-click="zoomOut()">zoom_out</md-icon>
</div>
</div>
I have a year directive:
angular.module("app").directive("year", ['$rootScope', function ($rootScope) {
return {
link: function($scope, element, attr) {
var events = element;
$scope.zoomIn = function(ev) {
console.log('zoomin');
$scope.zoom = $scope.zoom + $scope.scale;
if($scope.zoom < 100) { $scope.zoom = 100; }
events.html($scope.zoom);
events.css({
'width': $scope.zoom + '%'
});
}
$scope.zoomOut = function(ev) {
$scope.zoom = $scope.zoom - $scope.scale;
if($scope.zoom < 100) { $scope.zoom = 100; }
events.css({
'width': $scope.zoom + '%'
});
}
}
}
}]);
However the width is only applied to the very last year element. Why is that?
You are overwriting the scope every time. So each instance of your year directive is clobbering the zoomIn and zoomOut methods each time it is instantiated.
Normally you could solve this by using a new or isolate scope in your directive definition object:
//new scope
{
scope: true
}
//isolate scope
{
scope: {}
}
However, since you want to bind click handlers outside your individual year directives you will have to do something else.
A better solution would be to pass in the attributes and simply respond to their changes:
return {
scope: {
zoom: '='
},
link: function(scope, elem, attrs){
scope.$watch('zoom', function(){
//Do something with 'scope.zoom'
});
}
};
Now your external zoomIn and zoomOut functions can just modify some zoom property on the parent scope, and you can bind your year components to that.
<year zoom="myZoomNumber"></year>
And just for posterity, here is a working snippet.
function EventsController() {
var $this = this;
var zoom = 1;
$this.zoom = zoom;
$this.zoomIn = function() {
zoom *= 1.1;
$this.zoom = zoom;
console.log({
name: 'zoomIn',
value: zoom
});
};
$this.zoomOut = function() {
zoom *= 0.9;
$this.zoom = zoom;
console.log({
name: 'zoomOut',
value: zoom
});
};
}
function YearDirective() {
return {
restrict: 'E',
template: '<h1 ng-transclude></h1>',
transclude: true,
scope: {
zoom: '='
},
link: function(scope, elem, attr) {
var target = elem.find('h1')[0];
scope.$watch('zoom', function() {
var scaleStr = "scale(" + scope.zoom + "," + scope.zoom + ")";
console.log({
elem: target,
transform: scaleStr
});
target.style.transform = scaleStr;
target.style.transformOrigin = 'left';
});
}
};
}
var mod = angular.module('my-app', []);
mod
.controller('eventsCtrl', EventsController)
.directive('year', YearDirective);
.scaling{
z-index:1000;
position:fixed;
top:10px;
left:10px;
}
.behind{
margin-top:50px;
z-index:-1;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="my-app" ng-controller="eventsCtrl as $ctrl">
<div class="scaling">
<button type="button" aria-label="Zoom In" ng-click="$ctrl.zoomIn()">zoom_in</button>
<button type="button" aria-label="Zoom Out" ng-click="$ctrl.zoomOut()">zoom_out</button>
</div>
<div class="behind">
<year zoom="$ctrl.zoom">year 1</year>
<year zoom="$ctrl.zoom">year 2</year>
<year zoom="$ctrl.zoom">year 3</year>
<year zoom="$ctrl.zoom">year 4</year>
</div>
</div>
The events.css is getting over-ridden, thus making it apply only to last element.
events.css({
'width': $scope.zoom + '%'
}).bind(this);
You have to bind it to current scope.
I have an AnuglarJS app, where I load/change some images from a webservice...
Controller
.controller('PlayerCtrl', function($scope, programService) {
....
programService.refresh(function(data) {
$scope.program = data;
});
....
Template
<img src="{{program.image}}" />
When my app updates from the webservice the images changes as expected, I just want to make an fadeout / fadein when this happens, how can that be done?
Is it possible to always make a fadeout/in when a image src changes?
Thanks for the responses -
I ended up doing this, and it works ;)
--- Directive ---
.directive('fadeIn', function($timeout){
return {
restrict: 'A',
link: function($scope, $element, attrs){
$element.addClass("ng-hide-remove");
$element.on('load', function() {
$element.addClass("ng-hide-add");
});
}
};
})
--- Template ---
<img ng-src="{{program.image}}" class="animate-show" fade-in />
--- CSS ---
.animate-show.ng-hide-add, .animate-show.ng-hide-remove {
transition: all linear 0.5s;
display: block !important;
}
.animate-show.ng-hide-add.ng-hide-add-active, .animate-show.ng-hide-remove {
opacity: 0;
}
.animate-show.ng-hide-add, .animate-show.ng-hide-remove.ng-hide-remove-active {
opacity: 1;
}
Update 1.5.x - with Angular 1.5.x you can use ngAnimateSwap to achieve this effect.
Based on pkdkk's answer and the Angular.js 1.3.6 sources, my solution is as such (the CSS animation part is as used for standard ngShow):
// Copied from the Angular's sources.
var NG_HIDE_CLASS = 'ng-hide';
var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
app.directive('myFadeIn', function($animate, $timeout) {
return {
restrict: 'A',
link: function(scope, element, attrs){
element.addClass("ng-hide");
element.on('load', function() {
$timeout(function () {
$animate.removeClass(element, NG_HIDE_CLASS, {
tempClasses: NG_HIDE_IN_PROGRESS_CLASS
});
});
});
}
}
});
As christoph has mentioned, you should watch using $watch on the image source change.
But first make sure you use the ng-src rather than the src for the image tag.
<image id="new" ng-src="program.image" />
$scope.$watch('program.image', function(newValue, oldValue) {
if(newValue===oldValue) return;
$('img#new').hide();
$('img#new').fadeIn("slow", function() {});
})
In case others end up here wanting to perform animations on change of a background image, I'll post what I ended up using.
This directive assumes it's attached to a template like this:
<!-- Full screen background image and scarecrow for onload event-->
<div class="full-screen-image" data-background-image="{{backgroundImageUrl}}"></div>
<img class="hidden-full-screen-image hidden" data-ng-src="{{backgroundImageUrl}}"></div>
We want to set the background image source for the <div>, but attach an onload event so we know when the new image has arrived. To do that, we use an <img> with a .hidden class that has .hidden {display: none;}. Then we use the following directive to dynamically set the div's background image source and perform a fade to white then back from white on image change:
/***
*
* Directive to dynamically set background images when
* controllers update their backgroundImageUrl scope
* variables
*
* Template: <div data-background-image="{{backgroundImageUrl}}" />
* AND <img data-background-image="{{backgroundImageUrl}}" class="image-onload-target hidden" />
*
***/
var angular = require('angular');
angular.module('BackgroundImage', [])
.directive('backgroundImage', [
"$timeout",
function ($timeout) {
return function(scope, element, attrs){
attrs.$observe('backgroundImage', function(value) {
/***
*
* Define a callback to trigger once the image loads.
* The value provided to this callback = the value
* passed to attrs.$observe() above
*
***/
var imageLoadedCallback = function(value) {
// once the image load event triggers, remove the event
// listener to ensure the event is called only once
fadeOut();
target.removeEventListener('load', imageLoadedCallback);
$timeout(function() {
fadeIn(value);
}, 700);
}
/***
*
* Define fade in / out events to be called once a new image
* is passed to the attrs.backgroundImage in the directive
*
***/
var fadeOut = function() {
element.css({'opacity': '0'})
};
var fadeIn = function(value) {
element.css({
'background': 'url(' + value +') no-repeat center center fixed',
'background-size' : 'cover',
'opacity': '1'
});
};
// add an onload event to the hidden-full-screen-image
var target = document.querySelector('.image-onload-target');
target.addEventListener('load', imageLoadedCallback(value));
});
};
}]);
Working with Angular makes me love React all the more...
I know its late but according to #Aides answer i am posting here an working example that how can you achieve animation with change in ng-src using ngAnimateSwap (with Angular 1.5.x). I hope this helps someone in future:
HTML Markup:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-ngAnimateSwap-directive-production</title>
<link href="animations.css" rel="stylesheet" type="text/css">
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="//code.angularjs.org/snapshot/angular-animate.js"></script>
<script src="script.js"></script>
<script type="text/javascript">
angular.element(document.getElementsByTagName('head')).append(angular.element('<base href="' + window.location.pathname + '" />'));
</script>
</head>
<body ng-app="ngAnimateSwapExample" ng-controller="AppCtrl">
<div class="container">
<img ng-animate-swap="activeImage" class="cell swap-animation" ng-src="{{activeImage}}" alt="My Active Image" />
</div>
<div>
Current Image: {{activeImage}}
<br />
<button ng-click="previous()">Previous</button>
<button ng-click="next()">Next</button>
</div>
</body>
</html>
JS (script.js):
(function(angular) {
'use strict';
angular.module('ngAnimateSwapExample', ['ngAnimate'])
.controller('AppCtrl', ['$scope', '$timeout', function($scope, $timeout) {
var baseUrl = "http://lorempixel.com/400/200/sports";
$scope.images = [];
$scope.startIndex = 0;
for (var i = 0; i < 5; i++) {
$scope.images.push(baseUrl + "/" + i);
}
$scope.activeImage = $scope.images[$scope.startIndex];
/*
$interval(function() {
$scope.startIndex++;
if($scope.images[$scope.startIndex] && $scope.images[$scope.startIndex] != undefined){
$scope.activeImage = $scope.images[$scope.startIndex];
}
}, 2000);
*/
$scope.previous = function() {
$scope.startIndex--;
$timeout(function() {
if ($scope.images[$scope.startIndex] && $scope.images[$scope.startIndex] !== undefined) {
$scope.activeImage = $scope.images[$scope.startIndex];
}
}, 500);
};
$scope.next = function() {
$scope.startIndex++;
$timeout(function() {
if ($scope.images[$scope.startIndex] && $scope.images[$scope.startIndex] !== undefined) {
$scope.activeImage = $scope.images[$scope.startIndex];
}
}, 500);
};
}]);
})(window.angular);
Working plunker here.
My solution to this problem is to watch for changes on ng-src and using a timeout function to add a class which does the fadeIn effect.
HTML
<img ng-src="your-logic-will-go-here" class="animate-show ng-hide-add" fade-in>
Angular Code
.directive('fadeIn', function($timeout){
return {
restrict: 'A',
link: function($scope, $element, attrs){
$scope.$watch('selectedFormat.name', function(newValue, oldValue) {
if(newValue!=oldValue) {
$element.removeClass("ng-hide-add");
$element.addClass("ng-hide-remove");
$timeout(function () {
$element.addClass("ng-hide-add");
}, 100);
}
})
}
};
})
CSS
.animate-show.ng-hide-add, .animate-show.ng-hide-remove {
display: inline-block !important;
}
.animate-show.ng-hide-add.ng-hide-add-active, .animate-show.ng-hide-remove {
opacity: 0;
}
.animate-show.ng-hide-add{
transition: all linear 0.7s;
}
.animate-show.ng-hide-add, .animate-show.ng-hide-remove.ng-hide-remove-active {
opacity: 1;
}
You can't animate an img src change. You can, however, have multiple images and animate their opacity.
HTML/angular template
<div class="image-container">
<img src="image-one.jpg" ng-show="showImageOne">
<img src="image-two.jpg" ng-show="showImageTwo">
</div>
CSS
.image-container {
position: relative;
}
.image-container img {
position: absolute;
transition: 1s opacity linear;
}
.image-container img.ng-hide {
display: block!important;
opacity: 0;
}
I'm trying to access image src with controller to save it, but can not figure out how to do it.
My template:
<img data-ng-model="book.image"
style="width: 300px; height: 200px;"
ng-src="data:image/png;base64,iVBORw0K...SuQmCC">
<a data-ng-click="save(book)" class="btn">Submit</a>
My controller:
controller('BookEditController', [ '$scope', '$meteor', function ($scope, $meteor) {
$scope.save = function (book) {
if (typeof book == 'object') {
var books = $meteor("books");
var id = books.insert(book);
}
};
}])
One option is using a directive and applying a method called save to it which would handle the src attribute found on the image tag.
JS
var app = angular.module('myApp', []);
app.directive('saveImage', function () {
return {
transclude: true,
link: function (s, e, a, c) {
s.save=function(){
alert(a.src);
};
}
};
});
HTML
<div >
<img save-image style="width: 300px; height: 200px;" src="http://placehold.it/350x150"> <a ng-click="save()" class="btn">Submit</a>
</div>
This is the code implemented in jsfiddle.
Another option is to isolate the scope to a controller but still apply the image to it instead of a function.
JS
var app = angular.module('myApp', []);
app.directive('saveImage', function () {
return {
transclude: true,
link: function (s, e, a, c) {
s.image = a.src;
}
};
});
function cntl($scope) {
$scope.save = function (img) {
alert($scope.image || 'no image');
}
}
HTML
<div ng-controller='cntl'>
<img save-image style="width: 300px; height: 200px;" src="http://placehold.it/350x150"> <a ng-click="save()" class="btn">Submit</a>
</div>
Notice the added ng-controller="cntl".
This is the JSfiddle for that one.
There's probably a better way to do this... pass $event to your controller function
<a data-ng-click="save(book, $event)" class="btn">Submit</a>
and then use traversal methods to find the img tag and its src attr:
$scope.save = function (book, ev) {
console.log(angular.element(ev.srcElement).parent().find('img')[0].src);
...
Update: the better way is to create a directive (like #mitch did), but I would use = binding in an isolate scope to update a src property in the parent scope. (The = makes it clear that the directive may alter the scope. I think this is better than having a directive add a method or a property to the controller's scope "behind the scenes".)
<div ng-controller="MyCtrl">
<img save-image book="book1" src="http://placehold.it/350x150" >
Submit
</div>
function MyCtrl($scope) {
$scope.book1 = {title: "book1" }; // src will be added by directive
$scope.save = function(book) {
alert(book.title + ' ' + book.src);
}
}
app.directive('saveImage', function () {
return {
scope: { book: '=' },
link: function (s, e, a, c) {
s.book.src = a.src;
}
};
});
Plunker