Paper.js eraser tool made using layers and blendMode - javascript

I am making simple drawing app using Paper.js and Node.js. There are 2 layers:
- bottom layer with images
- top layer for drawing.
Layer with images is background to drawing layer.
I want to make a simple eraser tool which will erase drawing on a path. I'm trying to do it adding second path in my top layer which has blendMode set to "destination-out".
drawingLayer.activate();
path = new Path();
path.strokeColor = 'black';
path.strokeWidth = 5;
if (mode == "erase") {
path.strokeWidth = 15;
path.blendMode = 'destination-out';
}
My problem is that this "destination-out" path erases not only everything on top layer (drawing layer) but also everything on the bottom layer (images). Of course I want images to stay untouched by eraser. When I set some background in css for my page it is not erased by the eraser path.
Do you know a way to make eraser to modify one top layer while not modyfing bottom layer?

The solution is to activate the layer you want to erase in just before using the eraser tool, like this:
var firstLayer = paper.project.activeLayer; //This one is used to erase
var shapesLayer = new Layer(); // We don't want to erase on this one
so basically, when eraser tool is selected I do
firstLayer.activate();
Then when I want to draw shapes just activate the 'shapesLayer' the same way. This avoids the tool (the one used for erasing) touch anything from 'shapesLayer'

In order to do this, you have to encapsulate your drawings items and your eraser items into a group which has the blend mode source-over.
This way, the background items won't be affected by the eraser items destination-out blend mode.
Here's a simple sketch demonstrating this.
const backgroundCircle = new Path.Circle({
center: view.center,
radius: 50,
fillColor: 'orange'
});
const foregroundCircle = new Path.Circle({
center: view.center + 20,
radius: 50,
fillColor: 'blue'
});
const eraserCircle = new Path.Circle({
center: view.center + [10, 0],
radius: 50,
fillColor: 'black',
blendMode: 'destination-out'
});
const foreground = new Group({
children: [foregroundCircle, eraserCircle],
blendMode:'source-over'
});

Related

Openlayers how do you style drawn linestring different than what you are about to draw

I have a openlayers map which has draw interaction. When user starts drawing a linestring on the map, the portion of linestring drawn should look different than what the user would draw next.
In brief when user drops a point on the map, the line till that point should be block, without dash or any other styling options.
To illustrate what I am trying to do here goes the screenshot -
We can see user is about to add another point on the line so line till that point should turn block in blue color.
I have maintained the collection of points being added to the map, when user opts to delete the last point, it is being removed from the map but the last segment should also disappear from map. Can't find anything to achieve that.
Also I have added the ol.style.RegularShape() to display a square but it is displaying a circle instead don't know what I am doing wrong.
Here is jsbin link to my code - Draw interaction line style problem
You would need to use a style function for your draw style and divide the geometry into two parts for styling:
var drawStyle = function(feature) {
var styles = [];
if (feature.getGeometry().getType() == 'LineString') {
var coordinates = feature.getGeometry().getCoordinates();
styles.push(new ol.style.Style({
geometry: new ol.geom.LineString(coordinates.slice(-2)),
stroke: new ol.style.Stroke({
color: '#0000FF',
lineDash: [1, 20],
width: 5,
lineCap:'square',
lineJoin:'round',
lineDashOffset:10
})
}));
styles.push(new ol.style.Style({
geometry: new ol.geom.MultiPoint(coordinates),
image: new ol.style.RegularShape({
points: 4,
radius: 6,
angle: Math.PI / 4,
fill: new ol.style.Fill({
color: 'blue'
}),
stroke: new ol.style.Stroke({
color: 'blue'
}),
})
}));
if (coordinates.length > 2) {
styles.push(new ol.style.Style({
geometry: new ol.geom.LineString(coordinates.slice(0,-1)),
stroke: new ol.style.Stroke({
color: '#0000FF',
width: 2,
lineCap:'square',
lineJoin:'round'
})
}));
}
}
return styles;
}
To remove the last point from the line interaction simply use
line.removeLastPoint();
making sure var line; is declared so it is in the scope of the button click function

PaperJS updated centre not redrawing

I am using Paper.js to draw a circle on screen.
I update the centre position in update but the screen doesn't display draw the circle with the updated position.
class Ball{
this.graphics = new Path.Circle({
center: [200,200],
radius: 20,
fillColor: 'blue'
});
}
update(){
//test
this.graphics.center = [100,100]
}
}
var ball = new Ball();
//update
view.onFrame = function(event) {
ball.update();
}
The circle is always drawn on 200,200 no matter what values I update this.graphics.centre with.
I have also tried adding view.draw(); in view.onFrame() after ball.update() but it didn't change anything.
I have made sure the rest of the code is working since if I instead create a new Path.Circle() in ball.update() it draws a new circle on the correct position.

Google maps multi-color polyline

I have a Google maps page that draws various polylines based on a bunch of coordinates. They all connect two points via a great circle polyline. All lines have the same color. These lines are routes on a network
I would now like to make the polylines in a fading color to indicate the profitability of the route, showing a green color for profitable routes and red for loss making routes. As each polyline has two possible profitabilities (from both originating points) the colors should fade over to the other color gradually.
I assume, I could split the polyline into two, showing each only half of the line, but then the color would not gradually fade into the other.
Is there a way to do that?
Currently I am creating the lines as follows:
var routes = [['CJU', 'SZX', 33.5112991333, 126.49299621582, 22.6392993927, 113.81099700928, 1, 7, 3163768],
['CJU', 'PEK', 33.5112991333, 126.49299621582, 40.08010101318, 116.58499908447, 0.5, 4, 3163766],
['CJU', 'PVG', 33.5112991333, 126.49299621582, 31.14340019226, 121.80500030518, 0.5, 4, 3163767],
['CJU', 'WUH', 33.5112991333, 126.49299621582, 30.78380012512, 114.20800018311, 0.5, 4, 3163769],];
function setRoutes(map, flights) {
for (var j = 0; j < flights.length; j++) {
var route = flights[j];
var infowindow = new google.maps.InfoWindow({ content: 'From '+route[0]+' to '+route[1]+' ', position: new google.maps.LatLng(route[4], route[5]) });
var flt = new google.maps.Polyline({path: [new google.maps.LatLng(route[2], route[3]), new google.maps.LatLng(route[4], route[5])], strokeColor: "#FF0000", strokeOpacity: route[6], strokeWeight: route[7], geodesic: true, url: 'http://domain.com/page.asp?F='+route[8] });
flt.setMap(map);
google.maps.event.addListener(flt, 'click', function() { NewWindow(this.url,'name','770','490','Yes');return false; });
var apt = new google.maps.MarkerImage('http://domain.com/marker/dot.png', null, null, new google.maps.Point(8,14), new google.maps.Size(20,20));
var dep = new google.maps.LatLng(route[2], route[3]);
var marker = new google.maps.Marker({position: dep, map: map, icon: apt, title: route[0]});
var arr = new google.maps.LatLng(route[4], route[5]);
var marker = new google.maps.Marker({position: arr, map: map, icon: apt, title: route[1]});
}
}
setRoutes(map, routes);
This works just fine, but I'm not sure how I could have the color gradually fade over from a color1 to a color2.
Thanks in advance.
The google maps documentation does not have any option to fade colors.
They will appear fixed, However a little bit of customization can be done but fading from one color to another is not supported.
Try giving colors in RGBA mode.
I mean instead of Giving colors in Hex mode e.g. #FF0000, you can use it's equivalent in RGBA mode e.g. rgba(255, 0, 0, 1).
To fade your colors in RGBA mode, change the value of last digit and keep it between 0 (transparent) and 1 (visible).
You can use this link to convert your Hex colors to RGBA.

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();

In kinetic.js Issue with rotating a kinetic.group

I am using kinetic js. I am adding image, lines, etc to a kinetic.group and trying to rotate the group and it is getting rotated correctly. But after rotating the group, if I try to draw a line it is not correctly drawing on the present mouse position. It is drawing as it was before rotating.
The problem may be that if I rotate the group, the stage co-ordinates are not getting rotated it seems. What should I do to prevent this?
reference code---
var rootGroup = new Kinetic.Group({
x: stage.getWidth()/3,
y: stage.getWidth()/6,
draggable: true,
offset: [images.darthVader.width/2, images.darthVader.height/2]
});
rootGroup.add(line);
rootGroup.setRotationDeg(rootGroup.getRotationDeg()+90);
IN THIS WAY I AM DRAWING THE LINE.
var activeline = new Kinetic.Line({
points: [{x:0,y:0}],
stroke: "blue",
strokeWidth: 3,
lineCap: "round",
lineJoin: "round",
});
var mousePos = stage.getMousePosition();
points.push({
x: mousePos.x,
y: mousePos.y
});
activeline.setPoints(points);
rootGroup.add(activeline);
I'm not familiar with KineticJS, but it seems that you have to reset the transformation matrix back to its default state. OpenGL has the glLoadIdentity() method. Search for a similiar method on KineticJS.
See this tutorial
http://www.html5canvastutorials.com/advanced/html5-canvas-reset-transform-tutorial/
This should get you fairly close: http://jsfiddle.net/k4qB8/24/
// This rotates that added active line along with your group.
// This makes the draw direction correct
activeline.setRotationDeg(0-rootGroup.getRotationDeg());

Categories

Resources