I'm using Batik (svg-gen) to draw a svg (technical) diagram with the aid of java awt in a back-end service. I use this service on many places were the need arises to draw such diagram.
I would like to use a "tool-tip-kind-of-hover-over" to give more details on for instance a rectangle in the diagram.
Is this possible in Batik? I've found some hints on using css style but it strikes me as tricky.
I found out that its done by title, like described here. In order to include the title tag, the Batik classes that generate SVG and relevant AWT classes can be extended.
To start:
#Getter
public class TitledRectangle extends Rectangle {
private String title;
public TitledRectangle() {
}
public TitledRectangle(TitledRectangle r) {
super( r );
this.title = r.title;
}
// other constructors
}
And the corresponding batik class
public class PDSvgTitledRectangle extends SVGRectangle {
public PDSvgTitledRectangle(SVGGeneratorContext generatorContext) {
super( generatorContext );
}
public Element toSVG(TitledRectangle rect) {
Element element = super.toSVG( rect );
if ( rect.getTitle() != null ) {
Element svgTitle = super.generatorContext.getDOMFactory().createElementNS( "http://www.w3.org/2000/svg", "title" );
svgTitle.setTextContent( rect.getTitle() );
element.appendChild( svgTitle );
}
return element;
}
}
Now the new shape converter has to be used. That can be achieved by extending the SVGShape, responsible for writing the svg xml.
public class PDSvgShape extends SVGShape {
private PDSvgTitledRectangle titledRectangle;
public PDSvgShape(SVGGeneratorContext generatorContext) {
super( generatorContext );
titledRectangle = new PDSvgTitledRectangle( generatorContext );
}
public Element toSVG(Shape shape) {
if ( shape instanceof TitledRectangle ) {
return this.titledRectangle.toSVG( (TitledRectangle) shape );
}
return super.toSVG( shape );
}
}
And writing your own SVGGraphics2D (extending the existing one)
public class PDSvgGraphics2D extends SVGGraphics2D {
public PDSvgGraphics2D(Document domFactory) {
super( domFactory );
super.shapeConverter = new PDSvgShape( super.generatorCtx );
}
public PDSvgGraphics2D(Document domFactory, ImageHandler imageHandler, ExtensionHandler extensionHandler, boolean textAsShapes) {
super( domFactory, imageHandler, extensionHandler, textAsShapes );
super.shapeConverter = new PDSvgShape( buildSVGGeneratorContext( domFactory, imageHandler, extensionHandler ) );
}
public PDSvgGraphics2D(SVGGeneratorContext generatorCtx, boolean textAsShapes) {
super( generatorCtx, textAsShapes );
super.shapeConverter = new PDSvgShape( generatorCtx );
}
public PDSvgGraphics2D(PDSvgGraphics2D g) {
super( g );
super.shapeConverter = g.shapeConverter;
}
}
Now, there's the possibility to use the newly created awt extension:
PDSvgGraphics2D g = new PDSvgGraphics2D( ctx, false );
TitledRectangle rect = new TitledRectangle( x, y, w, h, "hello world!" ).
g.draw( rectangle );
Related
I want to use the ´bool DrawMode´ inside my ChangeDrawModeState class.
I need Something like ´GridState.drawMode´ but that does not work(drawMode is defined in GridState).
In the end I need to change the variable drawMode, if the RaisedButton gets Pressed. I'm not sure how to do this, cause the setState isnt working in the ChangeDrawModeState class as well. But isn't there a simple way to build a Button which turns a bool from True to false(or the other way around)?
class ChangeDrawMode extends StatefulWidget{
#override
ChangeDrawModeState createState(){
return new ChangeDrawModeState();
}
}
class ChangeDrawModeState<ChangeDrawMode>{
#override
Widget build(BuildContext context) {
return new RaisedButton(
child: new Text('Change Mode'),
textColor: Colors.white,
color: GridState.drawMode ? Colors.grey : Colors.blue,//HERE
onPressed: () =>setState(() => drawMode = !drawMode) //and HERE drawMode does not work
);
}
}
class Grid extends StatefulWidget {
#override
GridState createState() {
return new GridState();
}
}
class GridState extends State<Grid> {
bool drawMode = false;
final Set<int> selectedIndexes = Set<int>();
final key = GlobalKey();
final Set<_Foo> _trackTaped = Set<_Foo>();
_detectTapedItem(PointerEvent event) {
final RenderBox box = key.currentContext.findRenderObject();
final result = BoxHitTestResult();
Offset local = box.globalToLocal(event.position);
if (box.hitTest(result, position: local)) {
for (final hit in result.path) {
/// temporary variable so that the [is] allows access of [index]
final target = hit.target;
if (target is _Foo /*&& !_trackTaped.contains(target)*/) {
_trackTaped.add(target);
_selectIndex(target.index);
}
}
}
}
_selectIndex(int index) {
setState(
() {
if(selectedIndexes.contains(index)&&drawMode==false){
selectedIndexes.remove(index);
}
else if(drawMode==true){
selectedIndexes.add(index);
}
});
}
You can use InheritedWidget to update data and therefore widget state from any part of the app
Here is an example
I have two types edges in my supply chain model: demand_links and supply_links.
the default color is gray for all links. But I want to change the color of demand_links to red each time the attribute of the demand_link is changed (Note:the edge is the custom edge agent through edge creator). How to do this?
Below is my codes for simple test and it didn't work.
public class EdgeStyle2D extends DefaultStyleOGL2D {
#Override
public Color getColor(Object o){
// if (((CustomEdge) o).getCurrent_dl() == 1) {
// return Color.RED;
// }
// else {
// return Color.BLACK;
// }
if (o instanceof Distributor)
return Color.YELLOW;
return null;
}
}
I get the error when initialize.
Caused by: java.lang.ClassCastException: class supplyChainSystem.EdgeStyle2D cannot be cast to class repast.simphony.visualizationOGL2D.EdgeStyleOGL2D (supplyChainSystem.EdgeStyle2D and repast.simphony.visualizationOGL2D.EdgeStyleOGL2D are in unnamed module of loader repast.simphony.plugin.ExtendablePluginClassLoader #61af1510)
For styling links in this way, you should follow the example in the zombies.style.LinkStyle class within the Zombies_Demo model. Here's what the relevant parts of that class look like:
public class LinkStyle implements EdgeStyleOGL2D {
public Color getColor(RepastEdge<?> edge) {
BaseLink<?> link = (BaseLink<?>) edge;
return ReLogoSupport.lookupColor(link.getColor());
}
public int getLineWidth(RepastEdge<?> edge) {
return (int) (Math.abs(edge.getWeight()));
}
}
And you would use a class like this for the network (as opposed to agent) style.
I'd like to achieve something similar as "include" in android but in aurelia:
How to inject a plain html file content into my view, with binding evaluated within the parent View, and without using a custom element?
Binding innerhtml is not enough as, according to the doc, the bindings expressions are bypassed.
As already said by Ashley, using <compose view="./your-view.html"></compose> element will work with an existing HTML file and it will inherit the parent context.
If you want to compose HTML dynamically (from a file, database, or built-up programmatically) then using the ViewCompiler will give you the best performance and flexibility, as this is one layer less than compose compared to how aurelia builds custom elements internally.
I gave a similar answer to a different (but related) question here:
Aurelia dynamic binding
You'd use the text plugin to load your HTML file as text into a variable, and then pass that to the ViewCompiler. I have a custom element for this which, in terms of performance, is probably not better than compose but it does allow for more control when working with raw html as input and you could do your own performance optimizations specific to your situation as needed:
import * as markup from "text!./your-element.html";
export class SomeViewModel {
constructor() {
this.markup = markup;
}
}
And the view:
<template>
<dynamic-html html.bind="markup"></dynamic-html>
</template>
For completeness sake, here is the custom element I encapsulated the ViewCompiler in:
import {
customElement,
TaskQueue,
bindable,
ViewCompiler,
ViewSlot,
View,
ViewResources,
Container,
ViewFactory,
inlineView,
inject,
DOM
} from "aurelia-framework";
#customElement("dynamic-html")
#inlineView("<template><div></div></template>")
#inject(DOM.Element, TaskQueue, Container, ViewCompiler)
export class DynamicHtml {
#bindable()
public html: string;
public element: HTMLElement;
private tq: TaskQueue;
private container: Container;
private viewCompiler: ViewCompiler;
private runtimeView: View;
private runtimeViewSlot: ViewSlot;
private runtimeViewFactory: ViewFactory;
private runtimeViewAnchor: HTMLDivElement;
constructor(element, tq, container, viewCompiler) {
this.element = <HTMLElement>element;
this.tq = tq;
this.container = container;
this.viewCompiler = viewCompiler;
}
public bindingContext: any;
public overrideContext: any;
public bind(bindingContext: any, overrideContext: any): void {
this.bindingContext = bindingContext;
this.overrideContext = overrideContext;
if (this.html) {
this.htmlChanged(this.html, undefined);
}
}
public unbind(): void {
this.disposeView();
this.bindingContext = null;
this.overrideContext = null;
}
public needsApply: boolean = false;
public isAttached: boolean = false;
public attached(): void {
this.runtimeViewAnchor = <HTMLDivElement>this.element.firstElementChild;
this.isAttached = true;
if (this.needsApply) {
this.needsApply = false;
this.apply();
}
}
public detached(): void {
this.isAttached = false;
this.runtimeViewAnchor = null;
}
private htmlChanged(newValue: string, oldValue: void): void {
if (newValue) {
if (this.isAttached) {
this.tq.queueMicroTask(() => {
this.apply();
});
} else {
this.needsApply = true;
}
} else {
if (this.isApplied) {
this.disposeView();
}
}
}
private isApplied: boolean = false;
private apply(): void {
if (this.isApplied) {
this.disposeView();
}
this.compileView();
}
private disposeView(): void {
if (this.runtimeViewSlot) {
this.runtimeViewSlot.unbind();
this.runtimeViewSlot.detached();
this.runtimeViewSlot.removeAll();
this.runtimeViewSlot = null;
}
if (this.runtimeViewFactory) {
this.runtimeViewFactory = null;
}
if (this.runtimeView) {
this.runtimeView = null;
}
this.isApplied = false;
}
private compileView(): void {
this.runtimeViewFactory = createViewFactory(this.viewCompiler, this.container, this.html);
this.runtimeView = createView(this.runtimeViewFactory, this.container);
this.runtimeViewSlot = createViewSlot(this.runtimeViewAnchor);
this.runtimeViewSlot.add(this.runtimeView);
this.runtimeViewSlot.bind(this.bindingContext, this.overrideContext);
this.runtimeViewSlot.attached();
this.isApplied = true;
}
}
function createViewFactory(viewCompiler: ViewCompiler, container: Container, html: string): ViewFactory {
if (!html.startsWith("<template>")) {
html = `<template>${html}</template>`;
}
let viewResources: ViewResources = container.get(ViewResources);
let viewFactory = viewCompiler.compile(html, viewResources);
return viewFactory;
}
function createView(viewFactory: ViewFactory, container: Container): View {
let childContainer = container.createChild();
let view = viewFactory.create(childContainer);
return view;
}
function createViewSlot(containerElement: Element): ViewSlot {
let viewSlot = new ViewSlot(containerElement, true);
return viewSlot;
}
Jackson's Polymorphic Serialize/Deserialize capability is really cool, or would be if I could figure out how to apply it to my problem at hand. There is a pretty good article at http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html that I have been unable to adapt to my simplified problem.
In a nutshell, I am able to get Jackson 2.1.2 to Serialize a class hierarchy into JSON string with type information. I am unable, however, to get Jackson 2.1.2 to Deserialize that JSON String back into my class hierarchy. Below is a Unit Test that exposes this issue.
The class hierarchy is simple enough; Base Class with just two direct Subclasses. Further, the JSON output appears to respect my Jackson #JsonTypeInfo and produces a believable string from mapper.writeValueAsString
{"type":"dog","name":"King","breed":"Collie"}
But my call to mapper.readValue( jsonOfKing, Animal.class ) stacktraces with...
FAILED: testJacksonSerializeDeserialize
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class org.rekdev.fasterjacksonwtf.PolymorphismTests$Dog]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: java.io.StringReader#32b3a5a0; line: 1, column: 14]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObjectUsingNonDefault(BeanDeserializer.java:400)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:289)
....
Here's my unit test.
import org.testng.annotations.*;
import static org.testng.Assert.*;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.databind.*;
public class PolymorphismTests {
#Test
public void testJacksonSerializeDeserialize() throws Exception {
ObjectMapper mapper = new ObjectMapper();
Animal king = new Dog();
king.name = "King";
( (Dog) king ).breed = "Collie";
String jsonOfKing = mapper.writeValueAsString( king );
// JsonMappingException right here!
Animal actualKing = mapper.readValue( jsonOfKing, Animal.class );
assertEquals( king, actualKing );
}
#JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type" )
#JsonSubTypes( { #Type( value = Cat.class, name = "cat" ), #Type( value = Dog.class, name = "dog" ) } )
abstract class Animal {
public String name;
#Override
public abstract boolean equals( Object obj );
#Override
public abstract int hashCode();
}
class Dog extends Animal {
public String breed;
#Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
final Dog that = (Dog) obj;
boolean equals = name.equals( that.name ) && breed.equals( that.breed );
return equals;
}
#Override
public int hashCode() {
int hashCode = name.hashCode() + breed.hashCode();
return hashCode;
}
}
class Cat extends Animal {
public String favoriteToy;
#Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
final Cat that = (Cat) obj;
boolean equals = name.equals( that.name ) && favoriteToy.equals( that.favoriteToy );
return equals;
}
#Override
public int hashCode() {
int hashCode = name.hashCode() + favoriteToy.hashCode();
return hashCode;
}
}
}
Why won't the ObjectMapper allow me to readValue process the JSON produced by the ObjectMapper.writeValue()?
Make your inner classes static, like:
static class Dog extends Animal { ... }
otherwise things will not work (since non-static inner classes require so-called "implicit this" argument to refer to an instance of enclosing class).
Any idea how to configure SortedList whose elements are components register on the container in binsor.
Crud:ICrud
{
public SortedList<string, ICrudTransfer> Proxies
{
get { return _proxies;}
set { _proxies = value; }
}
}
I would like to do something like:
component ‘proxy1′, ICrudTransfer
component ‘proxy2′, ICrudTransfer
_proxies = SortedList[of string, ICrudTransfer]()
_proxies['url1']=#proxy1
_proxies['url2']=#proxy2
component ’service’, ICrud, Crud:
Proxies = _proxies
But it doesn't work
I would like to use such as properties, arrays or list. That works
component ’service’, ICrud, Crud:
CrudProxy = #proxy3
CrudProxies = (#proxy1 , #proxy2)
Thanks
Solution:
public class TestClass:ITestClass
{
IDictionary<string, IClass1> _dictGen = null;
IList<IClass1> _listGen = null;
public IList<IClass1> ListGeneric
{
get { return _listGen; }
set { _listGen = value; }
}
public IDictionary<string, IClass1> DictionaryGeneric
{
get { return _dictGen; }
set { _dictGen = value; }
}
}
component 'c1', IClass1, Class1
component 'c2', IClass1, Class1
component 'd', ITestClass, TestClass:
DictionaryGeneric = {key1:#c1,key2:#c2}
ListGeneric = (#c1,#c2)
Without generic (IList or IDictionary) seem not to work.