How to resize object without scaling pattern in FabricJS? - javascript

I'm wondering if there is an option to resize object without scaling its pattern in FabricJS?
Link to Fiddle
var canvas = window._canvas = new fabric.Canvas('c');
fabric.Image.fromURL('https://assets-cdn.github.com/images/modules/site/integrators/slackhq.png', function(img) {
var patternSourceCanvas = new fabric.StaticCanvas()
patternSourceCanvas.add(img)
patternSourceCanvas.setBackgroundColor('red', patternSourceCanvas.renderAll.bind(patternSourceCanvas))
patternSourceCanvas.setHeight(256);
patternSourceCanvas.setWidth(256);
var pattern = new fabric.Pattern({
source: function() {
return patternSourceCanvas.getElement();
},
repeat: 'no-repeat'
})
// create a rectangle object
var rect = new fabric.Rect({
fill: pattern,
width: 256,
height: 256
})
// "add" rectangle onto canvas
canvas.add(rect)
})
Any idea ?

Add this little code below. This will rescale the background pattern for you while scaling.
canvas.observe("object:scaling", function (e) {
var shape = e.target;
shape.width = shape.scaleX * shape.width;
shape.height = shape.scaleY * shape.height;
shape.scaleX = 1;
shape.scaleY = 1;
});

Related

TypeError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': Overload resolution failed

I'm trying to create a 3d customizer using fabricjs as canvas texture for three js model. I load obj file like this
function loadObj() {
canvasTexture.anisotropy = renderer.capabilities.getMaxAnisotropy();
textureMaterial = new THREE.MeshPhongMaterial({ map: canvasTexture });
texture.needsUpdate = true;
var loader = new THREE.OBJLoader2(manager);
loader.load('assets/men/cat1/model1.obj', function (data) {
if (object != null) {
scene.remove(object);
}
object = null;
object = data.detail.loaderRootNode;
materials = [];
object.traverse(function (child) {
if (child.isMesh) {
child.material.map = textureMaterial;
};
});
console.log(object.children[0].material)
object.children[0].material = textureMaterial;
render();
var scale = height / 5;
object.scale.set(scale, scale, scale);
object.position.set(0, -scale * 1.25, 0);
object.rotation.set(0, Math.PI / 2, 0);
object.receiveShadow = true;
object.castShadow = true;
scene.add(object);
});
}
and here's my fabric js
var canvas = new fabric.Canvas("canvas");
canvas.backgroundColor = "#FFBE9F";
var text = new fabric.IText('Three.js\n+\nFaBric.js', {
fontSize: 100,
textAlign: 'center',
fontWeight: 'bold',
left: 500,
top: 500,
originX: 'center',
originY: 'center',
selectable: true // make this object selectable
});
fabric.loadSVGFromURL('assets/men/cat1/prod1/pattern.svg', function (objects, options) {
var svgData = fabric.util.groupSVGElements(objects, { selectable: false,crossOrigin: 'anonymous' });
svgData.top = 420;
svgData.left = 70;
canvas.add(svgData);
canvas.sendToBack(svgData);
});
canvas.add(text);
var texture = new THREE.Texture(document.getElementById("canvas"));
fabric.Image.fromURL('assets/men/cat1/texture.png', function (myImg) {
var img1 = myImg.set({ left: 0, top: 0, selectable: false,crossOrigin: 'anonymous' });
canvas.add(img1);
canvas.sendToBack(img1);
});
and my 3d model is all black like this
anyone have any idea how to fix this? i want to wrap my fabricjs canvas to my 3d model
After i find several solution, i found that this problem is has the same solution to this post how to load fabricjs as texture for obj using threejs
the problem was i use fabricjs canvas as argument for THREE.Texture which only support image, so i change it to canvas tag instead, read above post hope it helps someone.

Adding Arrows or Overlay animation in Flight Animation example in OpenLayers 6

I want to add moving arrows or overlay animation in the Flights Animation example in OpenLayers 6.
I tried doing the overlay moving animation with JavaScript setInterval(), but so far I have only succeeded in animating a single LineString, that too after the line is finished drawing. I wanted to add the moving animation as the line is being drawn, kind of like tracing the LineString's path.
Can someone please help me with this?
Following is the code snippet where I have tried to add the moving animation:
var markerEl = document.getElementById('geo-marker');
var marker = new Overlay({
positioning: 'center-center',
offset: [0, 0],
element: markerEl,
stopEvent: false
});
map.addOverlay(marker);
function animateFlights(event) {
var coords;
var vectorContext = getVectorContext(event);
var frameState = event.frameState;
var features = flightSource.getFeatures();
for (var i = 0; i < features.length; i++) {
var feature = features[i];
if (!feature.get('finished')) {
coords = feature.getGeometry().getCoordinates();
var elapsedTime = frameState.time - feature.get('start');
var elapsedPoints = elapsedTime * pointsPerMs;
if (elapsedPoints >= coords.length) {
feature.set('finished', true);
}
var maxIndex = Math.min(elapsedPoints, coords.length);
var currentLine = new LineString(coords.slice(0, maxIndex));
vectorContext.setStyle(strokeStyle1);
vectorContext.drawGeometry(currentLine);
if (feature.get('finished')) {
var interval = setInterval(
function () { return animatePath(coords, interval) }, 10);
}
}
}
map.render();
}
function animatePath(path, clearInterval) {
if (i == path.length) {
stopAnimatePath(clearInterval);
}
marker.setPosition(path[i]);
i = i + 1;
}
function stopAnimatePath(clearInterval) {
clearInterval(clearInterval);
}
Here is a link to a snapshot of how my app looks right now
Trace your LineString
It should be enough to set your map center to the last point of your LineString if you update often enough
map.getView().setCenter(lastPoint)
If it gets laggy use
var pan = ol.animation.pan({
source: map.getView().getCenter()
});
map.beforeRender(pan);
map.getView().setCenter(lastPoint);
Draw arrows
To draw arrows on your LineString you can use the following style
var styleFunction = function (feature) {
var geometry = feature.getGeometry();
var styles = [
// linestring
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#000',
width: 2
})
})
];
geometry.forEachSegment(function (start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
styles.push(new ol.style.Style({
geometry: new ol.geom.Point(end),
image: new ol.style.RegularShape({
fill: new ol.style.Fill({color: '#000'}),
points: 3,
radius: 8,
rotation: -rotation,
angle: Math.PI / 2 // rotate 90°
})
}));
});
return styles;
};
more details: https://stackoverflow.com/a/58237497/546526

How to add a new canvas with animation in openlayers3 or openlayers4

I had drawn an animation in canvas like this and rendered a map using openlayers4. I want to add this canvas to the map[openlayers canvas] in next step.
I had used ol.source.ImageCanvas add a boundary to openlayers, so I try to add the canvas with animation using ImageCanvas, but failed.
What's more, openlayers API said ol.source.ImageCanvas method only the image canvas can be added. I didn't know whether the animate canvas so does.
Should I insit on using ImageCanvas method or try others?
Can someone give me an example if I abandon the ImageCanvas method?
After some tries, I got a solution! Haha!
First: the ol.source.ImageCanvas can still use, but you will get a stopped animate just like a screenshot.
Second: must know the ol.map.render() in openlayers3 or openlayers4, whose description is:
Request a map rendering (at the next animation frame).
Thus, you can use it to refresh the map and get the next animation of canvas.
The following is snippets of my code:
var topoCanvas = function(extent, resolution, pixelRatio, size, projection) {
// topo features;
var features = topojson.feature(tokyo, tokyo.objects.counties);
var canvasWidth = size[0];
var canvasHeight = size[1];
var canvas = d3.select(document.createElement('canvas'));
canvas.attr('width', canvasWidth).attr('height', canvasHeight);
var context = canvas.node().getContext('2d');
var d3Projection = d3.geo.mercator().scale(1).translate([0, 0]);
var d3Path = d3.geo.path().projection(d3Projection);
var pixelBounds = d3Path.bounds(features);
var pixelBoundsWidth = pixelBounds[1][0] - pixelBounds[0][0];
var pixelBoundsHeight = pixelBounds[1][1] - pixelBounds[0][1];
var geoBounds = d3.geo.bounds(features);
var geoBoundsLeftBottom = ol.proj.transform(geoBounds[0], 'EPSG:4326', projection);
var geoBoundsRightTop = ol.proj.transform(geoBounds[1], 'EPSG:4326', projection);
var geoBoundsWidth = geoBoundsRightTop[0] - geoBoundsLeftBottom[0];
if (geoBoundsWidth < 0) {
geoBoundsWidth += ol.extent.getWidth(projection.getExtent());
}
var geoBoundsHeight = geoBoundsRightTop[1] - geoBoundsLeftBottom[1];
var widthResolution = geoBoundsWidth / pixelBoundsWidth;
var heightResolution = geoBoundsHeight / pixelBoundsHeight;
var r = Math.max(widthResolution, heightResolution);
var scale = r / (resolution / pixelRatio);
var center = ol.proj.transform(ol.extent.getCenter(extent), projection, 'EPSG:4326');
d3Projection.scale(scale).center(center).translate([canvasWidth / 2, canvasHeight / 2]);
d3Path = d3Path.projection(d3Projection).context(context);
d3Path(features);
context.stroke();
// above code is add a topoJson boundary to canvas
// below code is add an animation to canvas
var settings = createSettings(tokyo, {
width: canvasWidth,
height: canvasHeight
});
// reset the projection and bounds for animation canvas
settings.projection = d3Projection;
settings.bounds = geoBounds;
var mesh = buildMeshes(tokyo, settings);
when(render(settings, mesh, {
width: canvasWidth,
height: canvasHeight
})).then(function(masks) {
when(interpolateField(stations, data, settings, masks)).then(function(field) {
// wind moving animation
animate(settings, field, canvas);
// refresh the map to get animation
window.setInterval(function() {
map.render();
}, 50);
});
});
return canvas[0][0];
}

How to add pattern with Image and Color in FabricJs

Is there any option to add pattern with Image AND Color?
Anytime, when I apply an image as a pattern, even though the image is transparent, Fabric adds it with some kind of "gray layer".
Link to Fiddler
var canvas = window.canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({
width: 256,
height: 256,
fill: 'red'
});
canvas.add(rect);
rect.center().setCoords();
fabric.util.loadImage('https://assets-cdn.github.com/images/modules/site/integrators/slackhq.png', function (img) {
rect.setPatternFill({
source: img,
repeat: 'no-repeat'
});
canvas.renderAll();
});
Any idea?
Assuming the image has transparent background, you can use fabric.StaticCanvas as fabric.Pattern's source:
var imgPath = 'https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png'
var imgColor = 'grey'
var canvas = this.__canvas = new fabric.Canvas('c')
fabric.Image.fromURL(imgPath, function(img) {
var patternSourceCanvas = new fabric.StaticCanvas()
patternSourceCanvas.add(img)
patternSourceCanvas.setBackgroundColor(imgColor, patternSourceCanvas.renderAll.bind(patternSourceCanvas))
var pattern = new fabric.Pattern({
source: function() {
return patternSourceCanvas.getElement();
},
repeat: 'repeat'
})
// create a rectangle object
var rect = new fabric.Rect({
fill: pattern,
width: 400,
height: 400
})
// "add" rectangle onto canvas
canvas.add(rect)
})
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.min.js"></script>
<canvas id="c" width="500" height="500"></canvas>

How to draw one object within another and never move outside of that object

i am working with fabric js and i want to draw two objects within canvas and when second object is drawn it should be drawn inside first object and never move outside the first object.I have tried this code
$(document).ready(function () {
var canvas = new fabric.Canvas('demo');
var rec = new fabric.Rect({
width: 200,
height: 100,
top: 10,
fill: 'blue',
});
rec.name = 'aaa';
canvas.add(rec);
canvas.on('object:moving', function (e) {
var h = rec.top;
var w = rec.width;
var obj = e.target;
obj.setCoords();
var rect = obj.getBoundingRect;
if(rect > h){
rect.top = Math.max(rect.top, rect.top-rect.getBoundingRect().top);
// alert(rect.top);
}
});
var text=new fabric.IText('Jayesh');
canvas.add(text);
});
Thanks in advance.Pls help

Categories