fabricjs cloned object affect old(default) object - clone

I am trying to get shadow Image of Text object without affecting the output of fabric.
Code
var clonedText = jQuery.extend({}, obj);
clonedText.fill = "rgba(50,50,50,0.5)";
imageURL = clonedText.toDataURL({format:'png'});
Result
Default:
AfterRun:
How can it be fixed?
I mean how can I copy object so that cant affect default image?
UPDATE:
I also tried this and this.
canvas._objects.forEach(function(obj, index){
var clonedText = fabric.util.object.clone(obj);
clonedText.fill = "rgba(50,50,50,0.5)";
imageURL = clonedText.toDataURL({format:'png'});
});
This has same result.

So you should not really clone instances like you would clone javascript objects.
Fabric objects can have references to canvas elements, image elements, deep structures, and every clone logic works on its own.
on fabricjs docs is specified that fabric.util.object.extende/clone does not clones fabricJS objects:
http://fabricjs.com/docs/fabric.util.object.html
Also in the docs is specified the clone method:
So you have to run
myText.clone(function(cloned) {
// do something with cloned....
});
If you are in need of a full syncronous process, and you are not using patterns or image sources for text you can also do:
var objectForm = myText.toObject();
var clonedText = new fabric.Text(objectForm.text, objectForm);

Related

amCharts: Map Recentering after JSON DataSource Despite Previous chart.homeGeoPoint

I'm mapping a series of points with amChart; after loading the data from an external JSON source, the map re-centers instead of staying at the point I'd set earlier with chart.homeGeoPoint.
I believe I need to use an event listener and set the homeGeoPoint after the map renders the points... but I'm at a bit of a loss; the only events I've found are from dataSource.events, and those appear to be related to fetching/parsing the JSON, as opposed to rendering the map.
// Create map instance
var chart = am4core.create("chartdiv", am4maps.MapChart);
// Set map definition
chart.geodata = am4geodata_region_world_northAmericaLow;
// Set projection
chart.projection = new am4maps.projections.Miller();
// Initial Position / Zoom
chart.homeZoomLevel = 2.6;
chart.homeGeoPoint = {
latitude: 39,
longitude: -96.2456
};
// Series for World map
var worldSeries = chart.series.push(new am4maps.MapPolygonSeries());
worldSeries.useGeodata = true;
// Markers
// Create image series
var imageSeries = chart.series.push(new am4maps.MapImageSeries());
// Create a circle image in image series template so it gets replicated to all new images
var imageSeriesTemplate = imageSeries.mapImages.template;
var circle = imageSeriesTemplate.createChild(am4core.Circle);
circle.radius = 5;
circle.fill = am4core.color("#116ad6");
circle.stroke = am4core.color("#FFFFFF");
circle.strokeWidth = 2;
circle.nonScaling = true;
circle.tooltipText = "{title}";
// Set property fields
imageSeriesTemplate.propertyFields.latitude = "latitude";
imageSeriesTemplate.propertyFields.longitude = "longitude";
imageSeriesTemplate.propertyFields.url = "url";
// Load data
imageSeries.dataSource.url = "/foo/map-points.php";
imageSeries.dataSource.parser = new am4core.JSONParser();
imageSeries.dataSource.parser.options.emptyAs = 0;
// Center after render
imageSeries.dataSource.events.on("done", function(ev) {
// This doesn't work - perhaps it is firing too early?
chart.homeGeoPoint = {
latitude: 39,
longitude: -96.2456
};
});
By request, here is a foo.json file for expirmenting with.
[{"title":"ISP","url":"\/airport\/kisp\/","latitude":40.7952,"longitude":-73.1002},{"title":"AEX","url":"\/airport\/kaex\/","latitude":31.3274,"longitude":-92.5486}]
What do I need to do to make sure the map stays centered on my desired location after the JSON data are loaded and rendered?
I've created an issue on GitHub in regards to why the map re-positions on the MapImageSeries' dataSource load and how to better work with that. (If you've a GitHub account, please subscribe to the issue.)
In the meantime, presuming the first time your dataSource gets its data that the user hasn't moved the map and we want to maintain homeGeoPoint as the current center, we can chain events to achieve that.
When the dataSource is "done" with its data, that doesn't necessarily imply anything has been done on the actual map level. The data still needs to propagate to the MapImageSeries, that still needs to create MapImages per data item, have the data validated/parsed there, and for whatever reason the map position shifts around. So the first time that happens (using events.once instead of events.on), we then listen for the MapImageSeries' "datavalidated" event also only one time (because "datavalidated" will have run before this, e.g. as soon as you create the MapImageSeries, if no data is supplied or it's taking some time, it will still run the event and the "inited" event, i.e. I guess you can say the series itself will successfully render nothing).
And to center the map we use chart.goHome(0);, this method will zoom to your homeGeoPoint and homeZoomLevel, the 0 is for how long the animation duration should run, i.e. just do the work, don't animate.
So all that together will look something like this:
// Center after render
imageSeries.dataSource.events.once("done", function(ev) {
imageSeries.events.once("datavalidated", function() {
chart.goHome(0);
});
});
Here's a demo:
https://codepen.io/team/amcharts/pen/239bfdc8689c65468df32d71b29759b8
Even though the map does re-position once the MapImageSeries loads, then it re-centers with the above code, I haven't actually seen the map shift at all anymore. So it looks to me the above code is doing the job of maintaining the homeGeoPoint. Let me know if that is still the case once implemented in your application.

How to delete MapImage from Ammap.js

I have been using Ammap Library and created Map.
https://www.amcharts.com/demos/custom-html-elements-map-markers/
I want to delete Map images object by using method(), Details are in below link.
Could any one let me know how to use this method()
https://docs.amcharts.com/3/javascriptmaps/MapImage#deleteObject
Method Name:"deleteObject()"
Thanks in Advance
deleteObject is a member method of the image/object itself, so you just call it from the object you want to delete, e.g.
image.deleteObject();
If your map is using custom HTML elements like in the demo, you also need to remove the div generated in your createCustomMarker method by calling removeChild in the DOM. You need to be able to access that div somehow, so I recommend modifying it to set the div's id to something you can look up later like the image's id:
// this function creates and returns a new marker element
function createCustomMarker(image) {
// create holder
var holder = document.createElement("div");
holder.className = "map-marker";
holder.title = image.title;
holder.id = image.id; //added to make div lookup easier
// ...
}
This modification assumes you set an id in your images, which is also recommended since you can use the getObjectById method to get the image object and call its deleteObject method.
Here's a sample function that deletes both the image and custom marker when an image ID is provided:
function deleteImage(imageId) {
var image = map.getObjectById(imageId);
var imageDiv;
if (image) {
image.deleteObject(); //delete the ammap image object
imageDiv = document.getElementById(imageId); //get the custom marker div
imageDiv.parentNode.removeChild(imageDiv); //remove it from the DOM
}
}
Demo - Click on the buttons to delete the corresponding marker.

canvas.toDataURL() - For bigger canvas-image

I would like to two show a Chart and also present an url with a link to a bigger Chart. The small preview-image looks and works fine:
<canvas id="image"></canvas>
var ct1 = document.getElementById("image").getContext("2d");
ct1.canvas.width = document.getElementById("image").offsetWidth;
ct1.canvas.height = document.getElementById("image").offsetHeight;
var Chart1 = new Chart(ct1).Line(lineChartData1,options);
The canvas is wrapped in a div, that's why offsetWidth and offsetHeight (to fill this additional div-element). Cause of the responsive-design there is no fixed image. Anyway, this works perfectly. For the URL to the "bigger" image I want to have the URL. I know the toDataURL() will help.
var url = document.getElementById("image").toDataURL();
document.write(url);
There are two disturbing problems with it:
The URL with this way exisists and, but the image has no content.
I also want to give the canvas-image a new size, like I managed with ct1.canvas.width and ct1.canvas.height, but it seems I cannot add this to the toDataURL.
What's wrong with the code?
Okay, I think I got it. Chart.js is animating the charts, so the toDataURL() I mentioned in my first question rendered only an empty image. We have to initiate the toDataURL, not before the animation is done. We handle that with the options:
var options = {
onAnimationComplete: done
}
and a tiny function:
function done() {
console.log('done');
var url=document.getElementById("canvas").toDataURL();
document.getElementById("canvas_link").href=url;
}
I think that's all.

fabricjs how to pass canvas from one page to another

I have a canvas on one page that is built using fabricjs
can i send that canvas to another page so that it retains all its objects as it is with all their properties and attributes to be same aswell.
Sure you can, just export your canvas to JSON
var canvas = new fabric.Canvas('c');
data = JSON.stringify(canvas)
Now you can send that data using a post request or store it in a database or whatever you want.
canvas.loadFromJSON(data, canvas.renderAll.bind(canvas));
Example: http://jsfiddle.net/P9cEf/3/
The example uses two canvases one page, but the concept is the same.
Edit:
To download the image client side
var canvas1 = document.getElementById("c");
var image = canvas1.toDataURL("image/png").replace("image/png", "image/octet-stream");
window.location.href = image;

Load image and change width and height as3

i want to load image from remote url and synchronicity and change it width and height.
i am using the folowwing code, but it want let me change the width and highet, i think i needto convert the loader to a Bitmap object.
how can i do that, thank you very much.
var imageURLRequest:URLRequest = new URLRequest(pic);
var myImageLoader:Loader = new Loader();
myImageLoader.load(imageURLRequest);
var urlRequest:URLRequest = new URLRequest(pic);
var loader:Loader = new Loader();
loader.load(urlRequest);
trace(loader.width); // return 0
loader.width =100; //dosent work
allMC[i].img.addChild(loader);
To access what the loader loaded, use loader.content reference. If you are loading an image, you can retrieve its raw data via (loader.content as Bitmap).bitmapData, of course first check if it's so via if (loader.content is Bitmap). Also, you need to do all of this after your loader will finish loading, it'll send an event indicating this.
...
loader.load(urlRequest);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
...
private function loaderComplete(e:Event):void {
// now your image is fully loaded
trace(loader.content.width);
// etc etc, whatever you need to do with your image prior to
// addressing it from elsewhere.
}

Resources