Apply Multiple Filters - konvajs

Dispite the tutorial here https://konvajs.org/docs/filters/Multiple_Filters.html of using multiple filters, I have been unsuccessful in applying multiple to an image in a NodeJS space.
Here is an example of the "fun" I went through trying to get it to work:
(Konva, layer, imageNode) => {
console.log('Callback');
imageNode.cache();
// imageNode.filters([
// Konva.Filters.Brighten,
// Konva.Filters.HSL,
// ]);
imageNode.filters([Konva.Filters.Posterize]);
imageNode.levels(0.8); // between 0 and 1
// imageNode.brightness(0.8);
// imageNode.contrast(0.8);
// imageNode.saturation(0.8);
// imageNode.cache();
// imageNode.filters([
// // Konva.Filters.Brighten,
// Konva.Filters.HSL,
// ]);
// imageNode.hue(0.5);
// imageNode.saturation(0.8);
// imageNode.luminance(0.85);
imageNode.cache();
As you can see, I'm trying to use a mix of brightness, contrast, saturation, hue, lumiance; however some work, some don't, and it all doesn't seem very reliable and if any work, only one ever does.
So how do I for example, brighten, and saturate an image?
Example Image I would like to "bring into the light" by adjusting different factors of it.
My end goal is something like this:
Update #1
No Luck, I cannot even get brightness to work on a small 50x35 image:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva#8.3.12/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Image Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
var layer = new Konva.Layer();
// main API:
var imageObj = new Image();
imageObj.onload = function () {
var imageNode = new Konva.Image({
x: 0,
y: 0,
image: imageObj,
width: 50, // 2048 / 2,
height: 35, // 1440 / 2,
});
imageNode.cache({ pixelRatio: 1})
imageNode.filters([
Konva.Filters.Brighten,
// Konva.Filters.HSL,
// Konva.Filters.Invert
]);
// imageNode.filters([Konva.Filters.Posterize]);
// imageNode.levels(0.2); // between 0 and 1
imageNode.brightness(0.8);
// imageNode.contrast(0.8);
// imageNode.saturation(0.8);
// imageNode.cache({ pixelRatio: 1})
// imageNode.filters([
// // Konva.Filters.Brighten,
// Konva.Filters.HSL,
// ]);
// imageNode.hue(0.5);
// imageNode.saturation(0.8);
// imageNode.luminance(0.85);
// imageNode.cache({ pixelRatio: 1})
layer.add(imageNode);
stage.add(layer);
};
imageObj.src = 'C:/Users/<User>/Downloads/Small.png';
</script>
</body>
</html>
Update #2
Ok this seems to be firstly an issue with doing this off a local html file, as not even taking the code from https://konvajs.org/docs/filters/Brighten.html and swapping in an absolute path to a file on my machine, works.

Seems to be an issue with editing images on a local HTML file, something stops them actually taking the changes.

Related

Cartojs4 - markers with multivalues donut chart

I would like to create a marker as we can see in the Carto SalesQuest product.
I made a cluster map from my CARTOjs 4 following this article provided by CARTO
https://carto.com/blog/inside/tile-aggregation/
I can play with CARTOCSS to style my layer but I am wondering what would be the best practices / methodology to achieve such an example : see below
Multivalues donut chart, cluster markers as seen in CARTO Salesquest
My own version of clusters with CARTO JS 4
My code look like this (hidden API KEY)
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0" />
<meta charset="utf-8" />
<!-- Include Carto.js -->
<script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
<!-- Include Leaflet -->
<script src="https://unpkg.com/leaflet#1.2.0/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet#1.2.0/dist/leaflet.css" rel="stylesheet" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const map = L.map('map').setView([30, 0], 3);
L.tileLayer('http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', {
maxZoom: 18
}).addTo(map);
// define client
const client = new carto.Client({
apiKey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX',
username: 'anagraph-clement'
});
// define source of data using a SQL query
const source = new carto.source.SQL(`
select *, 1 as count from pochesfils_carto
`);
// Aggregation option
const aggregation = new carto.layer.Aggregation({
threshold: 5,
resolution: 32,
placement: carto.layer.Aggregation.placement.SAMPLE,
columns: {
total_agg: {
aggregateFunction: carto.layer.Aggregation.operation.SUM,
aggregatedColumn: "count"
}
}
});
// define CartoCSS code to style data on map
const style = new carto.style.CartoCSS(`
#layer {
marker-fill: ramp([total_agg], (#3288bd, #99d594, #e6f598, #ffffbf, #fee08b, #fc8d59, #d53e4f), quantiles);
marker-width: ramp([total_agg], 8 ,40 , quantiles);
marker-line-color: ramp([total_agg], (#5F4690, #1D6996, #38A6A5, #0F8554, #73AF48, #EDAD08, #E17C05, #CC503E, #94346E, #6F4070, #666666), (5,10,20,30,50,66,75,100,150), "=", category);
marker-line-width: 5;
marker-line-opacity: 0.75;
}
#layer::labels {
text-name: [total_agg];
text-face-name: 'DejaVu Sans Book';
text-size: 8;
text-fill: #FFFFFF;
text-label-position-tolerance: 0;
text-halo-radius: 1;
text-halo-fill: black;
text-allow-overlap: true;
text-placement: point;
text-placement-type: dummy;
}
`);
// create CARTO layer from source and style variables
// and defining the interactivity of columns
// when featureOver and featureClick events are executed
const cartolayer = new carto.layer.Layer(source, style, { aggregation });
// add CARTO layer to the client
client.addLayer(cartolayer);
// get tile from client and add them to the map object
client.getLeafletLayer().addTo(map);
</script>
</body>
</html>
Thak you for letting me know if you have any hint on this type of marker creation. (svg ? d3.js ? chart.js ? CARTOCSS + TurboCARTO ? etc...)
There's not much room to improve your styles, the donut chart is needing de-aggregated data which you don't have in an aggregated visualization. And on top of that, CartoCSS is not capable of rendering easily the "donut parts" because that would very likely involve quite a lot of trigonometry computation to set angles to start/stop the different parts of the chart. SalesQuest uses a leaflet plugin and traditional marker rendering directly in the browser loading GeoJSON data, instead of using CARTO Maps API. So to achieve that visualization you need to render the proper data using SQL API and then use pure Leaflet coding to render it as markers.
A quick google search gave me at least this and this to inspire yourself.

can openlayers 3 render the animated marker using gif

I wanna ask how to make the marker show animated gif picture like openlayers 2 do...it can show the animated marker..what I want is show animated gif marker not make a marker move..it is possible or not?
style = {
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
anchor: anchor,
opacity: 1,
src: 'https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif',
scale: 1,
};
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ (style))
});
var iconFeature = new ol.Feature({
position: data.coordinate,
geometry: new ol.geom.Point([0,0]),
});
iconFeature.setStyle(iconStyle);
How to make https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif displayed animated as a gif in a map? is it possible or not create animated features in openlayers 3..I don't find any article with contain this solving...thanks
Yes there is a way do it but is a bit tricky so I am not sure whether it fit to your needs.
You need to add a marker instead and use css to style the marker.
check this
your html with the dom element
<div id="map" class="map"></div>
<div id="marker" title="Marker"></div>
your js here
var layer = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
layers: [layer],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
// the position of your marker
var pos = ol.proj.fromLonLat([23.3725, 35.208889]);
var marker = new ol.Overlay({
position: pos,
positioning: 'center-center',
element: document.getElementById('marker'),
stopEvent: false
});
map.addOverlay(marker);
and your css here
#marker {
width: 365px;
height: 360px;
background: url("https://articulate-heroes.s3.amazonaws.com/uploads/rte/kgrtehja_DancingBannana.gif") no-repeat scroll 0% 0% transparent;
}
and a fiddle here with the dancing banana (nice gif though :)))) )
This can definitely be done with a feature or layer style, with the help of a gif decoder that extracts the frames from the gif and controls an animation. Using gifler, the relevant code could look something like this:
const gifUrl = "./data/kgrtehja_DancingBannana.gif";
const gif = gifler(gifUrl);
gif.frames(
document.createElement("canvas"),
(ctx, frame) => {
if (!iconFeature.getStyle()) {
iconFeature.setStyle(
new Style({
image: new Icon({
img: ctx.canvas,
imgSize: [frame.width, frame.height]
})
})
);
}
ctx.clearRect(0, 0, frame.width, frame.height);
ctx.drawImage(frame.buffer, frame.x, frame.y);
map.render();
},
true
);
The above code sets an icon style with the animated gif on an existing feature. The feature is stored in a variable iconFeature.
See https://codesandbox.io/s/beautiful-fire-cdrou?file=/main.js for a working example.
An alternative is to use two png images. An effect similar to a gif image can be obtained if you apply two different styles to the same layer using the setStyle () method with a setInterval () function. Ej:
Style1 = {
...
src: '../image1.png',
...
};
Style2 = {
...
src: '../image2.png',
...
};
iconFeature.setStyle(Style1);
then
var n = 0; // global
function changeStyleEvery (){
if (n == 0){
n = 1;
iconFeature.setStyle(Style1);
}else{
n = 0;
iconFeature.setStyle(Style2);
};
};
function applyInterval (){
setInterval(function(){changeStyleEvery(); }, 500);
};

OpenLayers: get pixel color from image layer

I have a simple map with a static pixel image layer:
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.13.0/css/ol.css" type="text/css">
<script src="http://openlayers.org/en/v3.13.0/build/ol.js"></script>
// reference to jquery here
</head>
<body>
<div id="map" class="map"></div>
<script>
var extent = [0, 0, 2000000, 2000000];
var projection = new ol.proj.Projection({
code: 'xkcd-image',
units: 'pixels',
extent: extent
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
image = new ol.layer.Image({
source: new ol.source.ImageStatic({
url: 'http://imgs.xkcd.com/comics/online_communities.png',
projection: projection,
imageExtent: extent
})
});
map.addLayer(image);
image.on('singleclick', function(evt) {
var xy = evt.pixel;
console.log(xy);
var canvasContext = $('.ol-unselectable')[0].getContext('2d');
var pixelAtClick = canvasContext.getImageData(xy[0], xy[1], 1, 1).data;
var red = pixelAtClick[0]; // green is [1] , blue is [2] , alpha is [4]
});
</script>
</body>
</html>
When clicking on the image I want to get the color of the pixel that I clicked on. As far as I understand the raster source example (http://openlayers.org/en/v3.13.0/examples/raster.html), this is only possible with raster sources so I converted the image into a raster source. (When I add that raster source to the layer, I get the message that this operation is insecure, so I still use the image to show on the map.)
Here (How to get a pixel's color value from an Openlayers 3 layer?) the color is read from evt.context. However, with me evt.context is undefined.
Addendum: There might be several image layers overlaying each other. I need to get the color from a single specific image layer.
So this isn't ideal but might send you along the right lines:
You can use the pixel xy of the click event to query the canvas object that openlayers creates and puts your map data onto.
map.on('singleclick', function(evt) {
var xy = evt.pixel;
var canvasContext = $('.ol-unselectable')[0].getContext('2d');
var pixelAtClick = canvasContext.getImageData(xy[0], xy[1], 1, 1).data;
var red = pixeAtClick[0]; // green is [1] , blue is [2] , alpha is [4]
});
This assumes that you are using jQuery and that the canvas is the first DOM element using the class '.ol-unselectable'.
Hope it helps.

Can't scroll over shape or image in ipad

When I create a shape or image and draw it onto the stage, on the iPad i cant scroll over the shape.
For example, if my stage is bigger than the iPad's dimensions in width or height and i want to perform a scroll to see the rest of the stage or image, the stage is locked thus not allowing me to scroll.
Can anyone explain my this is happening?
I have tried with native canvas image and this is not the case. Is this a bug? Below is my code.
var mode = "";
var points = [];
var templayer = new Kinetic.Layer();
var activeShape = '';
var color = '#46468f';
var opacity = 0.2;
var stroke;
var link;
var userMode = 'edit';
var stage = new Kinetic.Stage({
container: 'stage',
width: 768,
height: 844
});
var stageWidth = stage.getWidth();
var stageHeight = stage.getHeight();
//var background = new Kinetic.Layer();
//var bgImage = new Kinetic.Image('images/room2.jpg');
var layer = new Kinetic.Layer();
var rectGroup = new Kinetic.Group({
x: 0,
y: 0,
draggable: false
});
console.log('Adding group');
var rect = new Kinetic.Rect({
x: 0,
y: 0,
width: stageWidth,
height: stageHeight,
fill: color,
opacity: opacity,
stroke: 'black',
draggable: false,
listening: true,
name: 'rect',
type: 'productTouch',
strokeWidth: 2,
done: false
});
console.log('Adding layer');
var layer = new Kinetic.Layer();
rectGroup.add(rect);
layer.add(rectGroup);
layer.draw();
stage.add(layer);
I have had this same issue. Maybe it's one of these:
1...
Make sure some of these variables are not set... try commenting out any of these and see if the behavior changes...
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=3, minimum-scale=1, usr-scalable=no" />
2...
Check to see if you have enabled a css feature to allow scrolling to occur...
overflow-y: auto; (on some div you have?)
I fixed this bug when create layer
var layer = new Kinetic.Layer({hitGraphEnabled : false});
This is a bit of an ugly hack to try to imitate both pinchzoom and scrolling on the ipad with kinetic.js with the help of panzoom.js touchswipe.js and Jquery.kinetic.js (name is just coincidental)
https://github.com/timmywil/jquery.panzoom/blob/master/
http://davetayls.me/blog/2011/06/14/jquery-kinetic-plugin-smooth-scrolling/#disqus_thread
var isiPad = navigator.userAgent.match(/iPad/i) != null;
$(function() {
if(isiPad){
$('body, html').kinetic();
$("#wrapper").panzoom({
disablePan: true,
minScale: 1,
maxScale: 4
});
//Enable swiping...
$("#stage").swipe( {
//Generic swipe handler for all directions
swipe:function(event, direction, distance, duration, fingerCount, fingerData) {
$("#wrapper").panzoom("reset");
},
threshold:0
});
}
});

Easeljs addEventListener do not work when bitmap added to stage

I do not understand, why eventlistener (copied from demo) does not work, If I add an bitmap to stage. It seems that bitmap causes problem, because if I add another circle etc. the click works fine.
See example:
<!DOCTYPE html>
<html>
<head>
<title>EaselJS demo: Simple animation</title>
<link href="../_shared/demo.css" rel="stylesheet" type="text/css">
<script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
<script>
var stage, circle;
var counter = 0;
var ticounter = 0
var images = []
var mytext = 'kk';
var lepakko;
var mx = 0;
function init() {
stage = new createjs.Stage("demoCanvas");
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
circle.x = 500;
circle.y = 500;
stage.addChild(circle);
stage.update();
lepakko = new createjs.Bitmap("halloween-bat.png");
//Click works, if line below is commented out, why?
//stage.addChild(lepakko);
circle.addEventListener("click",circle_event);
stage.update();
}
function circle_event(event) {
alert("clicked");
};
</script>
</head>
<body onLoad="init();">
<canvas id="demoCanvas" width="700" height="700">
alternate content
</canvas>
</body>
</html>
The click should not work by default. EaselJS library needs explicit enabling of the mouseover event. You need to add:
stage.enableMouseOver(20);
after creating the stage. To change the cursor to a pointer when it's over the object there is a property in EaselJS called cursor:
// doesn't work, even if a function is decleared outside
// circle.addEventListener("mouseover", function() { document.body.style.cursor = "pointer"; });
// this works
circle.cursor = "pointer";
Method enableMouseOver is documented on EaselJS website. Do note that listening to mouseover and other events in EaselJS is a lot more demanding for a web browser.

Resources