Save canvas to image with all its object and back to canvas with all objects back for editing them - html

I am using fabrics JS for adding objects on canvas and then saving it in form of image. Now i want bring the image back to edit mode inside canvas.
You can get detailed idea about it at http://www.13thandmars.com/logo_studio/builder.html?project_id=17b36372c43c04044dd804454dfdf6e8
Add text will add an object to tshirt in above link.

You can save canvas as JSON and then can load it back from JSON
var myJson = JSON.stringify(canvas.toJSON(['left', 'top', 'lockMovementX', 'lockMovementY']));
canvas.loadFromJSON(myJson, function () {
//render the canvas
canvas.renderAll();
});

if i am not mistaken you say that the font property is missing?
if this is you problem please take a look ,
fabric DOES NOT convert all the object properties to Json when you convert the canvas with canvas.toJSON() , so when you are going to get back your canvas , the objects will not be complete (your custom properties will missing),
for example : myObj.material , myObj.size, myObj.clotheType etc.
you have to say to the prototype toObject function which properties you want to be converted also with canvas.toJSON(), in your code, the following is a snippet of my code:
fabric.Object.prototype.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
objectId: this.objectId,//my custom property
_controlsVisibility:this._getControlsVisibility(),//i want to keep controlsVisibility for my reasons
typeTable:this.typeTable,//my custom property
txtType:this.txtType, //my custom property
customOptions:this.customOptions//my custom object property
});
};
i hope that helps.

Related

Uncaught TypeError: Cannot read property 'setThemingColor' of null

I'm writing an extension for the Forge Viewer and I ran into this problem when trying to use the setThemingColor() method in the "load" part of the extension:
function extensaoteste(viewer, options) {
Autodesk.Viewing.Extension.call(this, viewer, options);
}
extensaoteste.prototype = Object.create(Autodesk.Viewing.Extension.prototype);
extensaoteste.prototype.constructor = extensaoteste;
extensaoteste.prototype.load = function() {
this.onSelectionBinded = this.onSelectionEvent.bind(this);
this.viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, this.onSelectionBinded);
this.viewer.setThemingColor(3554,new THREE.Vector4(255/255, 255/255, 102/255, 1));
The code goes on, but the rest works fine. As you can see, there is another part of the extension, with an event listener.
If I use the exact same line with the setThemingColor method in the extensaoteste.prototype.onSelectionEvent, it works perfectly. I understand it is the this.viewer part that isn't returning anything, however it works in the line above.
I have used the code from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/events/#step-2-listen-and-react-to-an-event as a template.
I know this is probably a silly question, but I really can't understand it. Thanks for your help!
This is happening because the model geometry was not fully loaded when the call was made to set color and the null reference was not called out on this.viewer but on the model object:
Viewer3D.prototype.setThemingColor = function(dbId, color, model, recursive) {
// use default RenderModel by default
model = model || this.model;
model.setThemingColor(dbId, color, recursive); // null reference here
// we changed the scene to apply theming => trigger re-render
this.impl.invalidate(true);
};
Try set color (and other fragment level operations) after the GEOMETRY_LOADED_EVENT is fired:
var viewer = this.viewer;
viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT,()=>viewer.setThemingColor(3554,new THREE.Vector4(255/255, 255/255, 102/255, 1));

How to handle $ctrl. in AngularJS?

I have a Methode from an API. It returns a promise which resolves to an $ctrl(?) object. This objects should contain a measurement and will be updated whenever it receive a new data.
getMeasurements.latest(filter) //only a object to filter through all measurements
.then(function (latestMeasurement) {
$ctrl.latestMeasurement = latestMeasurement;
});
My problem is that I don't know how to work with this data or display it in my html file. How does $ctrl work?
Here the documentation of the API
$ctrl is the view model object in your controller. This $ctrl is a name you choose (vm is another most common name), if you check your code you can see the definition as $ctrl = this;, so basically its the this keyword of the controller function.
So now if you are using $ctrl.latestMeasurement = 'someValue', then its like you are adding a property latestMeasurement to controller function.
Now how to use it in HTML?
To access the latestMeasurement property in HTML your code must have <h1>{{$ctrl.latestMeasurement}}</h1> (H1 tag is just an example.)
Here $ctrl is different from what I explained above on controller part. Here $ctrl is the value used for controllerAs property of the controller. But $ctrl is the default value of the controllerAs property, so your code may not have the controllerAs property defined, so Angular will take default value $ctrl in HTML.
This is where most people gets confused. So let me explain,
Assume in your new controller you have declared your this keyword to variable vm, and you set your controllerAs property to myCtrl, i.e;
controllerAs: 'myCtrl' while defining controller properties.
var vm = this; in your controller function.
In this case in js you have to use vm for setting values, and in HTML you have to use myCtrl. For example,
in JS controller function vm.test = 'Hello world';
in HTML <span ng-bind="myCtrl.test"></span>
The result Hello world will be displayed in your page.
Why $ctrl and not $scope?
The view model object model concept is introduced in AngularJS 1.5, it is actually part of migrating to Angular 2 where $scope no longer exsist. So in 1.5 they introduced new approch but did not removed $scope completely.
Hope the answer helped.
For basic Javascript concepts you can see http://javascriptissexy.com/16-javascript-concepts-you-must-know-well/
For more detailed AngularJS $ctrl concept you can see https://johnpapa.net/angularjss-controller-as-and-the-vm-variable/
I suppose you are toking about this.
In this case, the
$ctrl.latestMeasurement
can means:
$ctrl, the controller where you are running this code. You can change it by $scope for example, and get the same result.
latestMeasurement, the variable where you want to store the last value of the measurement.
To explain my point of view let see the code below
<div ng-app="MeasurementApp">
<div ng-controller="MeasurementController">
<h1>{{latestMeasurement2}}</h1>
</div>
</div>
There you can see a simple angularjs app that shows a variable called latestMeasurement2 in a div and its controller called MeasurementController. Then, to display the value let check your code.
angular.module('MeasurementApp', [])
// creating the controller
.controller('MeasurementController', function(c8yMeasurements, $scope) {
// creating the variable and let it empty by now.
$scope.latestMeasurement2 = "";
// Your code
var filter = {
device: 10300,
fragment: 'c8y_Temperature',
series: 'T'
};
var realtime = true;
c8yMeasurements.latest(filter, realtime)
.then(function (latestMeasurement) {
// The latestMeasurement is where the measurement comes
// Here we just assign it into our $scope.latestMeasurement2
$scope.latestMeasurement2 = latestMeasurement;
});
});
As the documentation says
// $scope.latestMeasurement2 will be updated as soon as a new measurement is received.
$scope.latestMeasurement2 = latestMeasurement;
Hope this helps!

Dynamically display a list of xml hotspots (for krpano) based on json list

A bit of a newbie question for xml/krpano,
I have a list of json items that I want to be dynamically loaded into XML <hotspots>. I can loop through each item in JavaScript but I have no clue how to do the same loop in XML!
Check out this picture:
Imagine that each rectangle with an image is one item in a JSON list. Each rectangle you see is a <hotspot>. Right now these three hotspots are hardcoded into the XML file, but I want to dynamically load hotspots based on how many JSON list items exist.
Here is one hotspot. If my json list has 16 items, I would expect 16 hotspots
to be loaded.
<!--* video image thumbnail *-->
<hotspot name="start" distorted="true"
url="/panorama/%$panoId%/thumb.png"
ath="0" atv="0"
ox="0" oy="36"
vr_timeout="2000"
zorder="99"
scale="0.8"
onclick="changepano( loadscene(video_scene, null, MERGE|KEEPVIEW|KEEPMOVING, BLEND(1)); );"
alpha="0.0"
onloaded="if(vr_start_done === true, removehotspot(start); start_vr(); , tween(alpha,1); );"
/>
Your question is about dynamically generating hotspots in KRPano from a JSON list.
It is not really clear to me the way you wrote your question if you want to read the JSON from KRPano XML file (let's say FROM KRPano) or if you are expecting to use Javascript to ask KRPano to produce the hotspots.
These are two completly distinct ways of doing it :)
Because I'm lazy and I suppose you want to deal with JSON in JS, I go for this solution...
Loading a JSON file from Javascript
Your KRPano project should look like a core HTML file presenting Javascript to embed the KRPano plugin.
There, you can declare a script content in your HTML in which you will parse your JSON content and you ask KRPano to generate a hotspot. This method should be called when you are sure KRPano is ready, or get it called from KRPano when it is ready, using "onready" attribute.
myHotspotList.json content:
var myHotspotList = [
{
name: "myFirstHotspot",
atv: 15.0,
ath: 56.5686,
url: "myHotspotImage.jpg"
}
];
tour.html content:
<html>
...
<script url="myHotspotList.json'></script>
<script>
function generateHotspots() {
// First, we get the KRPano plugin
var myKRPano = document.getElementById('krpanoSWFObject');
// Now we parse the JSON object
for(var idx in myHotspotList) {
// Get the current Hotspot data
var currHotspot = myHotspotList[idx];
// Ask KRPano to create a hotspot with our current name
myKRPano.call("addhotspot('"+ currHotspot.name +"');");
// Now set various attributes to this hotspot
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].atv, "+currHotspot.atv+");");
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].ath, "+currHotspot.ath+");");
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].url, '"+currHotspot.url+"');");
}
}
</script>
...
// When you ask for pano creation, give your generation method as callback
embedpano({target:"krpanoDIV", onready:generateHotspots});
...
</html>
I hope this help and you got the trick with calling JSON object attributes and all.
Regards

Google Maps V3 Infobox undefined on polygons

I have a spoke in my wheels and I am not sure how to sort this out. I have been struggling with it for a couple days and it isn't like a normal infobox as it is not set to a marker rather a polygon which is something new for me. I have polygons that display with data from an XML file and they show up fine. I have searched the web and got it to have the mouseover set up to where you mouseover a polygon the opacity changes and an infobox pops up. Problem is the infobox when it pop up shows "undefined" instead of the html I have set in it to display with data from the XML file.
Here is a link to the test map for example.
http://www.mesquiteweather.net/googlemap_poly.html
Here is a link to the XML file where I am just trying to show the elements events and expires in the info box.
http://www.mesquiteweather.net/xml/warnings_test.xml
This is the code I am working with to create the infoboxes and mouseover events
function attachPolygonInfoWindow(polygon, html, event, expires)
{
var html = "<strong>" + event + "</strong>";
eventWarnings.infoWindow = new google.maps.InfoWindow({content: html});
google.maps.event.addListener(eventWarnings, 'mouseover', function(e) {
var latLng = e.latLng;
this.setOptions({fillOpacity:80});
polygon.infoWindow.setPosition(latLng);
polygon.infoWindow.open(map);
});
google.maps.event.addListener(eventWarnings, 'mouseout', function() {
this.setOptions({fillOpacity:0.35});
polygon.infoWindow.close();
});
}
var polygon = new google.maps.Polygon(/* omitted for brevity */);
attachPolygonInfoWindow(eventWarnings);
eventWarnings.setMap(map);
}
});
I am pretty sure it is something easy I am overlooking but I haven't been able to find anything that pertains to my issue. I am just lucky I got the infobox to show at all as I have learned it's tricky since polygons don't have a true center and they are not set up like you would with a marker which I can handle.
If anyone has any suggestions please let me know.
-Thanks
You defined your attachPolygonInfoWindow function with 4 argument, but only provide one when you call it:
// definition
function attachPolygonInfoWindow(polygon, html, event, expires)
...
// call
attachPolygonInfoWindow(eventWarnings);
Probably you want (I don't see the html or expires parameters being used):
attachPolygonInfoWindow(eventWarnings, "", event, null);
The other option would be to change the definition to:
// definition
function attachPolygonInfoWindow(polygon, event, expires)
and the call to (assuming you are going to use "expires" for something):
attachPolygonInfoWindow(eventWarnings, event, expires);
As it doesn't look like you need to pass in that parameter (event is serving the function that I would expect it to serve).
Also, FYI, you have a "hanging comma" in your alertColors.js which make IE unhappy...
example

Get a users youtube feed with knockout js?

Is this possible.. here's what I have atm, but my data object is just returning a load of jargon, what am I doing wrong? Am I doing anything.. right, for that matter?
I basically want to print out a list of a users videos (thumbnail and title, and make each one a clickable link to the video itself)
Thanks!
$(document).ready(function(){
$player.init();
})
var $player = (function(){
var player = {};
player.init = function(){
//init Youtube knockout
player.initYoutubeKnockout();
}
player.knockoutModel = {
videoData : ko.observableArray([]),
}
player.initYoutubeKnockout = function()
{
//load the Youtube json feed
$.ajax({
url: 'http://gdata.youtube.com/feeds/api/users/USERNAME/uploads?v=2&alt=json',
type: 'GET',
dataType: 'jsonp',
data: {
count: 5
},
success: function(data, textStatus, xhr) {
player.doYoutubeKnockout(data.item);
}
});
}
player.doYoutubeKnockout = function( data )
{
player.knockoutModel.videoData(data);
ko.applyBindings(player.knockoutModel, $('#youtube-feed')[0]);
console.log($(this));
}
return player;
})();
Frankly you weren't doing much at all.
The JSON data you get back from YouTube is not from data.item, it's in a completely different structure.
I'm assuming you wish to get 5 uploads from the user. The parameter name would be max-results, not count.
Probably the only thing you did fine was set up the url but that's about it.
You need to examine how the JSON returned looks like. Check the API reference for the structure of an atom feed. This is in XML but the corresponding JSON responses will have pretty much the same format with some minor differences. Examine the object by writing it to the console to verify you're getting the right properties.
Once you understand that, you need to use the correct query to get what you're expecting. Check out their API reference on their query parameters.
To help simplify your knockout code, I would strongly recommend you take the response you get back and map it to an object with simplified property names. For instance, to get the thumbnails for an entry, you would have to access the media$group.media$thumbnail array. It would be easier if you can just access it through thumbnail.
Also, if your elements you are binding to need to bind multiple values, it would help to map the values in such a way that your bindings are made easier. For instance, when using the attr binding, you'd set up a property for each of the attributes you want to add. Instead you could just group all the properties in an object and bind to that.
I wrote up a fiddle applying all that I said above to do as you had asked for. This should help give you an idea of what you can do and how to do it.
Demo