Greeatings!
I'm using mxGraph and i impact with a problem. I need to create picture of created diagram on server. For this purposes i use default java servlet -java\examples\com\mxgraph\examples\web\ExportServlet.java
It's create picture, but in some cases i got inverted colors and increased fonts.
There is example of js code i use to send on server:
EditorUi.prototype.getImageXML = function(){
var graph = this.editor.graph;
var bounds = graph.getGraphBounds();
var vs = graph.view.scale;
// Resuable image export instance
var imgExport = new mxImageExport();
// New image export
var xmlDoc = mxUtils.createXmlDocument();
var root = xmlDoc.createElement('output');
xmlDoc.appendChild(root);
// Renders graph. Offset will be multiplied with state's scale when painting state.
var xmlCanvas = new mxXmlCanvas2D(root);
xmlCanvas.translate(Math.floor(( - bounds.x) / vs), Math.floor(( - bounds.y) / vs));
xmlCanvas.scale(1 / vs);
imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);
// Puts request data together
var w = Math.ceil(bounds.width / vs + 2);
var h = Math.ceil(bounds.height / vs + 2);
return {
xml: encodeURIComponent(mxUtils.getXml(root)),
width: w,
height: h
};
};
There is how diagram is looks like:
Part of diagramm, as it is
And there how diag look after export:
Image of diag created by servlet
Some colors are inverted and font is increased.
Is it bug or i go wrong somewhere?
Related
How would I adapt #ghettovoice JSFiddle that saves a map to PDF to save the map to a JPEG or PNG? I have no idea how to attempt this problem so ideally if you know hoe to do it you can explain the logic behind it.
exportMap: function () {
var map = this.$refs.map
map.once('rendercomplete', function () {
var mapCanvas = document.createElement('canvas');
var size = map.getSize();
mapCanvas.width = size[0];
mapCanvas.height = size[1];
var mapContext = mapCanvas.getContext('2d');
Array.prototype.forEach.call(
document.querySelectorAll('.ol-layer canvas'),
function (canvas) {
if (canvas.width > 0) {
var opacity = canvas.parentNode.style.opacity;
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
var transform = canvas.style.transform;
// Get the transform parameters from the style's transform matrix
var matrix = transform
.match(/^matrix\(([^(]*)\)$/)[1]
.split(',')
.map(Number);
// Apply the transform to the export map context
CanvasRenderingContext2D.prototype.setTransform.apply(
mapContext,
matrix
);
mapContext.drawImage(canvas, 0, 0);
}
}
);
if (navigator.msSaveBlob) {
// link download attribuute does not work on MS browsers
navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png');
} else {
var link = document.getElementById('image-download');
link.href = mapCanvas.toDataURL();
link.click();
}
});
map.renderSync();
}
The problem was a combination of missing dependencies (namely FileSaver.js and fakerator.js) and a cross origin server block (CORS block) (Browsers automatically prevent httpRequests to a different domain name unless the server allows it). The first one is fixed by installing the packages while the second one is resolved by setting the crossOrigin Attribute of the ImageWMSLayer to null in my case but possibly to 'Anonymous' for other sources. Hope this helped someone else :)
What are some common ways in ThreeJS to work with creating Meshes (consisting of Geometry and Materials) and then later deleting those objects?
My use case is to display lat/long points on a rotating 3D globe. Each point should be clickable and show further information. The points displayed should also be able to change based on data that is binded with Vue.
I currently use something like this but am running into memory leak issues:
var material = new THREE.MeshPhongMaterial({
color: 0xdc143c,
});
var cone = new THREE.Mesh(
new THREE.ConeBufferGeometry(radius, height, 8, 1, true),
material
);
cone.position.y = height * 0.5;
cone.rotation.x = Math.PI;
var sphere = new THREE.Mesh(
new THREE.SphereBufferGeometry(sphereRadius, 16, 8),
material
);
export default class Marker extends THREE.Object3D {
constructor() {
super();
this.name = "Marker";
this.add(cone, sphere);
}
destroy() {
this.remove(cone, sphere);
}
}
Are there libraries on top of Three that makes the management of Meshes/Materials/Geometry more simple to work with?
What I do is create a function in some utils file, and any time I need to dispose of a mesh, I pass the mesh in as the function parameter:
const removeMesh = (meshToRemove) => {
meshToRemove.visible = false;
scene.remove(meshToRemove);
meshToRemove.geometry.dispose();
meshToRemove.material.dispose();
meshToRemove= undefined;
}
I am posting sample code below please any help me
var bb_CoverPageImage = Ti.UI.createImageView({
width : '100%',
image : '',
categoryName : magazinePagesList[i].categoryName,
lengthId : magazinePagesList.length,
});
bb_CoverPageImage.image = L('Site_URL_Images') + magazinePagesList[i].imagePreviewUrl.replace(/\s/g, '%20');
coverScrollView.add(bb_CoverPageImage);
Though you have not mentioned why you need image width/height of remote image, but there can be basically 3 ways to get the width/height of any remote image.
Solution 1:
You can either ask your backend devs to provide you the image width & height as separate parameters.
Solution 2:
You can use Ti.UI.ImageView's load event to wait till your image is loaded & then you can use a code similar like this:
imageview.addEventListener('load', function(e) {
var image = imageview.toBlob();
var h = image.height;
var w = image.width;
});
This method forces that you can get width/height only after the image is loaded in ImageView.
Solution 3:
You can use web-service to download image & get further values:
var client = Ti.Network.createHTTPClient({
onload: function(e) {
var image = this.responseData;
var h = image.height;
var w = image.width;
bb_CoverPageImage.image = image;
},
onerror: function(e) {}
});
client.open("GET", magazinePagesList[i].imagePreviewUrl);
client.send();
I'm trying to figure out if there is a way of getting a callback once a texture has been updated? I'm swapping the geometry in the scene but sharing the same changing underlying texture based on a canvas and I'm noticing random corruption that eventually disappears as the program runs. I think this is as a result of thrashing that is causing the geometry changes to become unsynchronized with the texture updates.
So I realize the established mechanism is to set is needsUpdate = true on the texture and material, but can I know when that update has been applied so that I can add the new geometry to the scene? I think I am adding the geometry before that update actually gets to the gpu and using the old texture for random frames. Is this possible, or does the texture update definitely get processed before the scene is drawn?
If you can point me in the right direction it would be much appreciated.
Additionally I've added an update event listener to the material, which gets called frequently, but I still end up with the same issues relating to the texture update happening after the geometry has been updated.
Here is an example of what I mean, some code removed. The general idea is to share the same texture / material among many generated objects. Update the canvas, and then add the new object into the scene. This for the most part works under chrome, but occasionally glitches where a frame has the previous texture applied.
var material, texture, texture_canvas, context;
var frames = [];
var total_frames = 24;
var last_frame = undefined;
var current_frame = 0;
var scene;
function init() {
// initialize scene, etc
scene = new THREE.Scene();
// Set up render etc, omitted
texture_canvas = document.createElement('canvas');
texture_canvas.height = 1024;
texgture_canvas.width = 1024;
context = texture_canvas.getContext( '2d' );
context.fillStyle = '#000000';
context.fillRect( 0, 0,
texture_canvas.width,
texture_canvas.height );
texture = new THREE.Texture( this.texture_canvas );
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.generateMipmaps = false;
material = new THREE.MeshLambertMaterial({ map: texture } );
for (var i=0; i<total_frames; i++) {
var mesh = new THREE.Mesh( generate_geometry(), material );
frames.push(mesh);
}
}
function animate() {
if (last_frame) {
scene.remove(frames[last_frame]);
}
// Update / generate new canvas
context.drawImage( generate_image(), 0, 0 );
texture.needsUpdate = true;
material.needsUpdate = true;
frames[current_frame].uvsNeedUpdate = true;
scene.add(frames[current_frame % total_frames]);
last_frame = current_frame;
current_frame++;
requestAnimationFrame( animate );
}
From the sample I created
I am unable to set the circle's alpha / visiblity when mousedown draw line. But I am able to console log it when its detect hitTest.. Is there advise in this?
Below is the block of codes:
var canvas, stage;
var drawingCanvas;
var oldPt;
var oldMidPt;
var title;
var color;
var stroke;
var colors;
var index;
var rect, circle1;
var currMidPt;
$(document).ready(function() {
init();
});
function init() {
canvas = document.getElementById("canvas");
index = 0;
colors = ["#828b20", "#b0ac31", "#cbc53d", "#fad779", "#f9e4ad", "#faf2db", "#563512", "#9b4a0b", "#d36600", "#fe8a00", "#f9a71f"];
//check to see if we are running in a browser with touch support
stage = new createjs.Stage(canvas);
stage.autoClear = false;
stage.enableDOMEvents(true);
createjs.Touch.enable(stage);
createjs.Ticker.setFPS(24);
createjs.Ticker.on("tick", tick);
drawingCanvas = new createjs.Shape();
stage.addEventListener("stagemousedown", handleMouseDown);
stage.addEventListener("stagemouseup", handleMouseUp);
title = new createjs.Text("Click and Drag to draw", "36px Arial", "#777777");
title.x = 300;
title.y = 200;
rect = new createjs.Shape();
rect.graphics.beginFill("#000").drawRect(0, 0, stage.canvas.width, stage.canvas.height);
var container = new createjs.Container();
container.x = 0;
container.y = 0;
stage.addChild(container, title);
stage.addChild(drawingCanvas);
circle1 = new createjs.Shape();
circle1.graphics.beginFill("#990000").drawCircle(120,120,40);
container.addChild(circle1);
stage.update();
}
function handleMouseDown(event) {
if (!event.primary) { return; }
if (stage.contains(title)) {
stage.clear();
stage.removeChild(title);
}
color = colors[(index++) % colors.length];
stroke = Math.random() * 30 + 10 | 0;
oldPt = new createjs.Point(stage.mouseX, stage.mouseY);
oldMidPt = oldPt.clone();
stage.addEventListener("stagemousemove", handleMouseMove);
}
function handleMouseMove(event) {
if (!event.primary) { return; }
var midPt = new createjs.Point(oldPt.x + stage.mouseX >> 1, oldPt.y + stage.mouseY >> 1);
drawingCanvas.graphics.clear().setStrokeStyle(stroke, 'round', 'round').beginStroke(color).moveTo(midPt.x, midPt.y).curveTo(oldPt.x, oldPt.y, oldMidPt.x, oldMidPt.y);
oldPt.x = stage.mouseX;
oldPt.y = stage.mouseY;
oldMidPt.x = midPt.x;
oldMidPt.y = midPt.y;
currMidPt = midPt;
if(circle1.hitTest(currMidPt.x, currMidPt.y)) {
console.log('test');
circle1.alpha = 0.6;
circle1.visible = false;
}
stage.update();
}
function tick(event) {
// console.log(ndgmr.checkPixelCollision(drawingCanvas,circle1,0,false));
stage.update(event);
}
function handleMouseUp(event) {
if (!event.primary) { return; }
stage.removeEventListener("stagemousemove", handleMouseMove);
}
The main reason this doesn't work is because you are using a stage that never clears itself. This gives you the benefit of a "paint brush", since it just adds new curves as you draw, but the circle can never be removed, since it is painted on to the canvas. If you change the alpha, it just draws on top of the current circle. This is also why your circle gets all aliased, as it constantly draws on top of itself, multiplying the alpha.
Here is a quick edit that shows the circle moving its x position instead of adjusting the alpha. Any time you roll over the original position it will move 10 pixels to the right.
http://codepen.io/lannymcnie/pen/redrgo?editors=0010
The hitTest code you have used is not correct though, since it always checks the x/y position of the pen against the local coordinates of the circle -- this means the position of the circle doesn't matter. To fix this, you need to find the local coordinates instead:
currMidPt = circle1.globalToLocal(midPt.x, midPt.y);
Here is an updated fiddle showing that behaviour: http://codepen.io/lannymcnie/pen/grejVg?editors=0010
However, to get the effect you are probably looking for, you have to take a different approach. Instead of using the stage auto-clear, use a cached Shape, and update the cache when you draw. This will provide the paint effect, but let the rest of the stage get updated as usual.
// Remove this!
stage.autoClear = false;
// Cache the drawingCanvas once after creating it
drawingCanvas = new createjs.Shape();
drawingCanvas.cache(0,0,canvas.width,canvas.height);
// After drawing, update the cache. This is at the end of the mousemove function.
// Use "source-over" to apply the new contents on top, instead of clearing the cache.
drawingCanvas.updateCache("source-over");
stage.update();
I also made a few other changes:
Removed the Ticker listener that updates the stage. Your mousemove already updates the stage when the contents change. If you want to reintroduce the ticker update for other content, then remove the stage.update() calls everywhere else, as they are redundant.
Moved the drawingCanvas below the circle/container. This just makes sure the circle is always visible for the demo
Here is a final demo with these changes:
http://codepen.io/lannymcnie/pen/NNYLPX?editors=0010
Hope that helps!