Blending mode between konvajs and openlayers - javascript

I try to use blending mode between konvajs (https://konvajs.org/) and openlayers (https://openlayers.org/)
I have a map created with openlayers, then I use Overlay (https://openlayers.org/en/latest/examples/overlay.html) of openlayers to add canvas konvajs on over the map.
I've try:
property globalCompositeOperation of konvajs, but it works only with items in konvajs
css mix-blend-mode, but it all items in konvajs were stuck with the same mode, I want each items have different mode.
Is there any way to achieve this?
Here example code I tried with No.1 above:
https://codesandbox.io/s/cool-monad-ow21j?file=/main.js

To help investigate how OpenLayer and Konvajs canvas might interact I created the below snippet. This draws an Openlayer map element then adds a Konvajs canvas element. Both are positioned absolute so that they overlap. I threw in some simple rectangles with varying opacity to illustrate the possibility in case that was all you really require.
The image below shows the F12 inspector view of the elements. As we can see, label a points out that the OpenLayers element employs a dedicated canvas. Similarly, label b shows the Konvajs canvas.
The conclusion is that these elements are indeed separate HTML5 canvas elements. Therefore the question switches to 'is it possible to use blend mode across canvasses?'. Fortunately this has been asked before.
So, in answer to your question, 'Is there any way to achieve this [blend between OpenLayer and Konvajs] ?' the answer seems to be a definite maybe. However, looking at the potential approaches it would seem that you might lose some of the mouse/touch functionality of both of the canvas layers.
// Create the map element
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([-1.1656, 51.0856]),
zoom: 15
})
});
// Create the Konva element
var stage = new Konva.Stage({container: 'container1', width: 600, height: 400});
var layer1 = new Konva.Layer();
stage.add(layer1);
var rect = new Konva.Rect({x: 100, y: 25, width: 100, height: 50, fill: 'magenta', stroke: 'black', draggable: true });
layer1.add(rect);
rect = new Konva.Rect({x: 200, y: 75, width: 100, height: 50, fill: 'magenta', stroke: 'black', draggable: true, opacity: 0.5 });
layer1.add(rect);
rect = new Konva.Rect({x: 300, y: 125, width: 100, height: 50, fill: 'magenta', stroke: 'black', draggable: true, opacity: 0.25 });
layer1.add(rect);
stage.draw();
.map {
height: 400px;
width: 100%;
}
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.4.3/build/ol.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<div id="map" class="map" style="left: 0; top: 0; width: 600px; height: 400px; background-color: transparent; position: absolute;"></div>
<div id='container1' style="left: 0; top: 0; width: 600px; height: 400px; background-color: transparent; position: absolute;"></div>

Related

OpenLayers: Attaching an ground layer image over an large building

I've got the following task:
Attaching a ground layer (provided as an jpg-image) over an plant.
I thought that I've found an solution.
Live-Demo on CodePen: http://codepen.io/mizech/full/dXBoRq/
But it doesn't work as expected. If one zooms into or out the map the image doesn't scale bigger or smaller.
Moreover: The image is supposed to rotate with the map. That doesn't work neither.
Therefore my question:
What do I have to do to make it work the way it should (image scales when zoomed-in and -out, images follows when rotating) ?
Or should I choose a complete different approach?
Then any hints concerning code-examples are very appreciated.
Here my code so far:
var layer = new ol.layer.Tile({
source: new ol.source.OSM()
});
var control = new ol.control.FullScreen();
var center = ol.proj.transform([6.9690055, 49.2175355], 'EPSG:4326', 'EPSG:3857');
var overlay = new ol.Overlay({
position: center,
element: document.getElementById('plant')
});
var view = new ol.View({
center: center,
zoom: 17
});
var map = new ol.Map({
target: 'map',
layers: [layer],
controls: [control],
overlays: [overlay],
view: view
});
#plant {
width: 1300px;
height: 400px;
border: 1px solid black;
transform: rotate(16.5deg);
}
#plant img {
opacity: 0.6;
}
<div id="map" class="map">
<div id="plant"><img src="http://placehold.it/1300x400" alt="bild" /></div>
</div>
You can try to use another option to accomplish the preferred effect, there are two options I can think of:
1. Use ol.layer.Image(), code sample:
var extent = ol.proj.transformExtent([7.2, 49.3, 6.5, 49.1],
'EPSG:4326', 'EPSG:3857');
new ol.layer.Image({
opacity: 0.6,
source: new ol.source.ImageStatic({
url: 'http://placehold.it/1300x400',
imageExtent: extent
})
})
The extent is just a rough estimation yet.
2. Use a vector Layer to style an Icon using your image, already explained here:
https://gis.stackexchange.com/questions/130603/how-to-resize-a-feature-and-prevent-it-from-scaling-when-zooming-in-openlayers-3/
To rotate it along with the map use rotateWithView: true in your icon style, like this:
var iconStyle = new ol.style.Icon({
src: 'http://placehold.it/1300x400',
rotateWithView: true,
opacity: 0.6
});

Google Maps Hidden Div Overflows half map

I'm using Google maps, with Drawning Manager
var latlng = new google.maps.LatLng(41.7318187, 44.8627138);
var mapOptions = {
zoom: 8,
center: latlng,
disableDoubleClickZoom: true
}
bounds = new google.maps.LatLngBounds();
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
//Define a symbol using SVG path notation, with an opacity of 1.
var lineSymbol = {
path: 'M 0,-1 0,1',
strokeOpacity: 1,
scale: 4
};
drawingManager = new google.maps.drawing.DrawingManager({
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.MARKER,
google.maps.drawing.OverlayType.POLYLINE
]
},
markerOptions: {
icon: $imgFolderFullPath + '/' + $('#TourObjectType').val() + '.png',
draggable: true
},
polylineOptions: {
strokeColor: $("#LineType").val()
}
});
drawingManager.setMap(map);
The problem is when map renders some element that has visibility hidden and z-index 107 which overflows half of the map and i cant insert, edit, move, poly lines and markers in that part
DOM structure of the problematic part looks like this :
<div style="transform: translateZ(0px); position: absolute; left: 0px; top: 0px; z-index: 107; width: 100%;">
<div style="cursor: default; width: 53px; height: 191px; visibility: hidden;">...</div>
</div>
and also when i comment visibility hidden in the code snippet above, there is something like white comment box with star shown on the map
i what to know what causes the problem
This happens when the signed_in=true is used.
Bug report: https://code.google.com/p/gmaps-api-issues/issues/detail?id=7788
I added a link to this post in the bug report for reference. Hope Google will fix that very soon.
I can not tell you why this occurs, only that for me it also does in the example that is provided in the documentation. You can't draw in that area, but you can zoom into it, etc.
https://developers.google.com/maps/documentation/javascript/examples/drawing-tools.
EDIT: It seems to be a bug with the signed-in mode, as #MrUpsidown pointed out

Converting a 2d array to polygon points

Suppose you have a 2d array like the ones often used to organise tile maps, 1 represents solid tiles.
var map = [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
];
Instead of square tiles, I want to convert this shape in to points of a polygon. Each 1 in the array would have a set width and height like a tile map, but I only want the corner points necessary to recreate the shape as a solid polygon. I also want diagonal slopes instead of a step-like effect when the 1's are diagonal like in the array. I've played around and searched for an answer but I can't figure out the best way to do this, any ideas?
Thanks.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
<script defer="defer">
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var poly = new Kinetic.Line({
points: [73, 192, 73, 160, 340, 23, 500, 109, 499, 139, 342, 93],
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 5,
closed: true
});
// add the shape to the layer
layer.add(poly);
// add the layer to the stage
stage.add(layer);
</script>
</body>
</html>
You could put those points you want in the points array ,and use kinetic js for ur project.
Link : http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-polygon-tutorial/

Make kineticjs use existing canvas

I am attempting to use kinetic.js with an existing canvas. The problem is that the kinetic.js API requires that you specify the id of the container element and then kinetic.js creates a Kinetic.Stage (which creates and uses its own canvas).
For instance:
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var rect = new Kinetic.Rect({
x: 239,
y: 75,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4
});
// add the shape to the layer
layer.add(rect);
// add the layer to the stage
stage.add(layer);
</script>
I want to be able to use an existing canvas element with kinetic.js instead of it creating its own. Is this possible?
A similar question has been asked before, however it doesn't seem to provide a correct answer.
Any ideas? Thanks!
An html canvas is just a bunch of pixels.
You can convert those pixels into an image and then use that image as the source for a Kinetic.Image.
// create an image from the existing canvas
var canvas2Image=new Image();
canvas2Image.onload=function(){
// create a Kinetic.Image using that image
var kImage=new Kinetic.Image({
x:0,
y:0,
width:canvas2Image.width,
height:canvas2Image.height,
image:canvas2Image
});
}
canvas2Image.src=canvas.toDataURL();

Draw Multiple figures in a stage using Kineticjs?

I want to draw multiple figures on a canvas on different button clicks.
HTML
<body>
<div id="container">
</div>
<div id="option">
<button value="rect" onclick="rect();">rect</button>
<button value="circle" onclick="circle();">circle</button>
</div>
</body>
Javascript:
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer();
function rect(){
var redLine = new Kinetic.Line({
points: [100, 5, 100, 300, 450,300],
stroke: 'black',
strokeWidth: 3,
lineCap: 'square',
lineJoin: 'mitter'
});
// add the shape to the layer
layer.add(redLine);
// add the layer to the stage
stage.add(layer);
}
function circle(){
var wedge = new Kinetic.Wedge({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: 70,
angleDeg: 60,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
rotationDeg: -120
});
// add the shape to the layer
layer.add(wedge);
// add the layer to the stage
stage.add(layer);
}
But it gives error as layer and stage are not defined. How do I solve it ?
The reasons that stage and layer would not be defined are that either they are outside of scope, or your code is breaking before they are instantiated in the first place.
First, make sure that your stage and layer are outside of any functions; global scope.
Second, your functions 'circle()' and 'rect()' are being called with the button click, which I suspect is breaking your code. You want to remove this onclick handler from inline:
<button value="circle" onclick="circle();">circle</button>
and assign onclick using javascript, after you have created your stage. You can assign handlers easily using jQuery. So your code should look something like:
HTML
<button value="rect" id='rect'>rect</button> //assign an id to your button
JS
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer();
$('#yourButtonId').click(function(){ // button id here would be '#rect' if you use the id above
rect();
});

Categories

Resources