I'm using an old (2 years) leaflet plugin inside react to load a shape file ( a zip file that contains 4 files inside that when displayed on a map will draw a layer, commonly used on GIS)
While the plugin works (tested), I would like to eliminate the upload functionality. just call the zip file that I have inside my app and make it appear and disappear on the layers control menu in the top right of the map. That's it
Here is the https://codesandbox.io/s/34o825nz8m
I believe the trick is in here:
handleFile(e) {
var reader = new FileReader();
var file = e.target.files[0];
reader.onload = function(upload) {
this.readerLoad(upload);
}.bind(this);
reader.readAsArrayBuffer(file);
}
What I've tried so far:
replaced the var file for './protrac.zip' which is located here (https://www.data.boem.gov/Mapping/Files/protrac.zip)
got an error.
changed reader.readAsDataURL(file).
Since I've erased the input tag my intention is to run the handleFile function inside ComponentDidMount (). but I can't even console.log the zip that I have inside my app.
P.D. if you get a createLeafletElement () error, this can only be fixed on the node_modules folder by putting this line
ShapeFile.prototype.createLeafletElement = function createLeafletElement () {}
Related
I feel like I'm close but still missing something. Here's what I have so far
var files = window.files;
console.log(files) // => (3) [File, File, File]
// File objects:
// 0: File {correctName: 'test.bin', name: 'test.bin' …}
// 1: File {correctName: 'test.gltf', name: 'test.gltf', …}
// 2: File {correctName: 'test.png', name: 'teest.png', …}
var fi = new BABYLON.FilesInput(engine, scene, (s) => {
console.log('here in scene loaded callback');
})
fi.loadFiles({ dataTransfer: { files: asheFiles } });
The scene loaded callback never gets called however. I also don't see anything being rendered on the canvas element in the page.
I know there's clearly a way to do it based on the example they have here:
https://sandbox.babylonjs.com/
I'm just trying to figure out how to recreate that.
Okay folks, I do have a solution.
Overview
After searching through many of their documentation pages, forums online and similar questions here on Stackoverflow, I've realized that Babylon js doesn't really sport a direct file load API. They have functions that can take file objects as arguments, but ultimately that does not meet the needs of digesting a gltf file that's split up into various parts, namely .gltf, .png, and .bin. As using a provided method such as BABYLON.SceneLoader.Append on the gltf file will fail once BABYLON parses it and immediately starts requesting the accompanying files (.png and .bin) over the web. Here you could theoretically use a .glb file, but that's not the file format I'm using in my project.
You need to hack the library into allowing you to do what you need. I started looking at the example code used in the linked sandbox above. They use this FileInput class to somehow load all the accompanying files together after a drag and drop event. I emulated the drag and drop functionality via:
function sceneLoadedCB(newScene) { window.scene = newSene; initCamera(newScene, canvas); }
const fi = new BABYLON.FilesInput(engine, scene, sceneLoadedCB)
fi.loadFiles({
dataTransfer: { files: [gltfFileObject, pngFileObject, binFileObject] }
})
This would've been good enough for my purposes except that it will always create another scene object in place of the current one, stopping me from loading up a scene with multiple gltf objects. Asset containers will not work to solve this as they are always bound to the scene they are created with; you cannot transfer assets from one scene to another.
The solution
I didn't reverse engineer the logic that parses and groups the files as all being part of the same gltf object. But I did find this static property of the FilesInputStore class being used as a place to store actual javascript File objects. If you populate this store with your gltf file accompanying file assets you will be able to load them together as all being part of your gltf file.
Demo:
var theScene // your babylon scene instance
const renderLoop = (sceneToRender) => {
sceneToRender = sceneToRender || window.scene
sceneToRender.render();
sceneToRender.getEngine().runRenderLoop(renderLoop);
};
yourGLTFFiles.forEach((file) => {
window.BABYLON.FilesInputStore.FilesToLoad[file.name] = file
})
const gltfFile = yourGLTFFiles.find((file) => file.name.includes('gltf'))
BABYLON.SceneLoader.Append('file:', gltfFile, theScene, function (loadedScene) {
console.log('here in scene loaded callback, scene: ', loadedScene)
// below will be true since append adds to the scene instance you passed it
console.log(loadedScene === theScene)
renderLoop(theScene)
});
This took me forever to solve. I hope this solution saves you time in building your awesome project!
I am trying to build a Vue App and I am new to Vue, I am trying to load an image at runtime in Js/Ts with the code below
console.log("code is being called");
let image = new Image();
image.onload = (event) => {
console.log("image loaded");
}
image.src = "static/prison_tileset.png";
The code works fine on a regular html file, in Vue however, the onload method isn't being called. The first console.log is being called. I am sure that the image is found because if I manipulate the path to something wrong on purpose I get an error that the file isn't being found. It's just that the onload event isn't being firied.
I'd be very happy if somebody could help me with that!
I've gotten it to work now! I will answer the question myself as best as I can. To use local assets in view you have to load them via Webpack like this:
const Logo = require("../assets/logo.png");
this.image.src = Logo;
If you also happen to use electron you have to set the webSecurity in your entry file to false for electron to be allowed to access local files.
The desired results have been done in vanilla here
To be clear, I won't be using alert(), I'd like to place the dimensions in the state object.
How would I recreate this code in React under the OnChange() event handler?
React is still JavaScript, everything you do in regular js can be done in React. At a high level, React is just the framework that helps you create more modular reusable code.
With that being said, thinking as a React developer, you should create the upload process first get that to work in a separate class. The class could accept an image through its props. Then once that is working correctly you could create a Higher order component that wraps the upload component or rather receives the upload component as a parameter and checks the image size. At this point you can return an Invalid component or just process the image and upload.
You might want to look at a few tutorial on Getting started with React.
This is an excellent start egghead.io
I have a img src that looks something like this:
I was able to solve the problem with code like this
if (e.target.files && e.target.files[0]) {
var img = document.createElement("img");
this.state.backgroundImageFile = e.target.files[0];
img.onload = function () {
debugger;
console.log(this.width + " " + this.height);
});
var reader = new FileReader();
reader.onloadend = function (ended) {
img.src = ended.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
I'm new to JXA scripting, but I'm attempting to troubleshoot some older scripts currently in place here at work. They loop through an InDesign document and create several PDFs based on it. Previously, they would be stored in a folder called "~/PDFExports". However, this doesn't work with 10.10.
If I change the code to just place the PDFs in "~/", it works fine. From there, I'd like to move the files to "~/PDFExports", but I can't seem to find an answer on how to do that. I've seen things about making calls to ObjC, or to call Application('Finder'), but neither work - they both return undefined.
Am I just missing something basic here, or is it really this hard to simply move a file with JXA?
EDIT: Some syntax for how I'm creating the folder in question and how I'm attempting to work with Finder.
//This is called in the Main function of the script, on first run.
var exportFolder = new Folder(exportPath);
if(!exportFolder.exists) {
exportFolder.create();
}
//This is called right after the PDF is created. file is a reference to the
actual PDF file, and destination is a file path string.
function MoveFile(file,destination){
var Finder = Application("Finder");
Application('Finder').move(sourceFile, { to: destinationFolder });
alert("File moved");
}
Adobe apps have long included their own embedded JS interpreter, JS API, and .jsx filename extension. It has nothing to do with JXA, and is not compatible with it.
InDesign's JSX documentation:
http://www.adobe.com/devnet/indesign/documentation.html#idscripting
(BTW, I'd also strongly advise against using JXA for Adobe app automation as it has a lot of missing/broken features and application compatibility problems, and really isn't fit for production work.)
Here's the link to Adobe's InDesign Scripting forum, which is the best place to get help with JSX:
https://forums.adobe.com/community/indesign/indesign_scripting
You could use Cocoa to create the folder
var exportFolder = $.NSHomeDirectory().stringByAppendingPathComponent("PDFExports")
var fileManager = $.NSFileManager.defaultManager
var folderExists = fileManager.fileExistsAtPath(exportFolder)
if (!folderExists) {
fileManager.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(exportFolder, false, $(), $())
}
and to move a file
var success = fileManager.moveItemAtPathToPathError(sourceFile, destinationLocation, $());
if (success) alert("File moved");
Consider that destinationLocation must be the full path including the file name
and both sourceFile and destinationLocation must be NSString objects like exportFolder
Could it be that the folder is missing ? Could be your reference to the folder object not valid ? Any syntax to show ?
I will share some of what I learned about JXA move and duplicate methods. I am not a professional programmer just an attorney that is passionate about automation. My comments come from much trial and error, reading whatever I could find online, and A LOT of struggle. The move method does not work well with Finder. Use the System Events move method instead. The duplicate method in Finder works just fine. The duplicate method does not work well in system events. This is a modified snippet from a script I wrote showing move() using System Events.
(() => {
const strPathTargetFile = '/Users/bretfarve/Documents/MyFolderA/myFile.txt';
const strPathFolder = '/Users/bretfarve/Documents/MyFolderB/';
/* System Events Objects */
const SysEvents = Application('System Events');
const objPathFolder = SysEvents.aliases[strPathFolder];
SysEvents.move(SysEvents.aliases.byName(strPathTargetFile), {to: objPathFolder});
})();
I have a pretty JavaScript-heavy site that I'm working on, so to try and keep the code a little more under control, I tried to group my code into several logical external JavaScript files (.js files). For the most part it works just fine, but for some reason one function located in the file viewer.js file does not like being called from the ajax.js file (in other words, it's not - the Firebug console tells me nb_displayError is not defined (where the function in question is nb_displayError().
I tried placing the viewer.js script tag both above and below my ajax.js script tag in my HTML file, but neither seemed to make a difference. Strangely, I can call functions in my ajax.js file from another JavaScript file but this one in particular fails. Any thoughts as to why?
In case it's useful to you, the function calling creating this issue is defined as the following (I don't think it's anything particularly tricky):
function populateZoomLevel() {
var model = $('#modtype').children(':selected').text();
var lat = $("#loc-label").data('location').latitude;
var lon = $("#loc-label").data('location').longitude;
$.get("checkDomains.php", { result: 'zoomlevel', lat: lat, lon: lon, model: model })
.done(function(responseText){
if(responseText.substring(0, 7) == "error: "){ // Error flag
nb_displayError(responseText);
return; // Don't do anything further
}
$('#zoomlevel').html(responseText);
});
}