Skip to content

Commit

Permalink
Add support for foreignObject
Browse files Browse the repository at this point in the history
  • Loading branch information
planger committed Apr 3, 2020
1 parent c5d5e7e commit 5cf9917
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 14 deletions.
6 changes: 4 additions & 2 deletions examples/svg/src/di.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2017-2018 TypeFox and others.
* Copyright (c) 2017-2020 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -17,7 +17,8 @@
import { Container, ContainerModule } from "inversify";
import {
TYPES, ConsoleLogger, LogLevel, loadDefaultModules, LocalModelSource, PreRenderedView,
SvgViewportView, ViewportRootElement, ShapedPreRenderedElement, configureModelElement
SvgViewportView, ViewportRootElement, ShapedPreRenderedElement, configureModelElement,
ForeignObjectElement, ForeignObjectView
} from "../../../src";

export default () => {
Expand All @@ -31,6 +32,7 @@ export default () => {
const context = { bind, unbind, isBound, rebind };
configureModelElement(context, 'svg', ViewportRootElement, SvgViewportView);
configureModelElement(context, 'pre-rendered', ShapedPreRenderedElement, PreRenderedView);
configureModelElement(context, 'foreign-object', ForeignObjectElement, ForeignObjectView);
});

const container = new Container();
Expand Down
13 changes: 10 additions & 3 deletions examples/svg/src/standalone.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2017-2018 TypeFox and others.
* Copyright (c) 2017-2020 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -14,7 +14,7 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { LocalModelSource, TYPES, SModelRootSchema, ShapedPreRenderedElementSchema } from "../../../src";
import { LocalModelSource, TYPES, SModelRootSchema, ShapedPreRenderedElementSchema, ForeignObjectElementSchema } from "../../../src";
import createContainer from "./di.config";

function loadFile(path: string): Promise<string> {
Expand Down Expand Up @@ -53,7 +53,14 @@ export default function runMulticore() {
id: 'tiger',
position: { x: 400, y: 0 },
code: tiger
} as ShapedPreRenderedElementSchema
} as ShapedPreRenderedElementSchema,
{
type: 'foreign-object',
id: 'direct-html',
position: { x: 50, y: 350 },
size: { height: 50, width: 190 },
code: "<p>This is a free-floating HTML paragraph!</p>"
} as ForeignObjectElementSchema
]
};

Expand Down
4 changes: 2 additions & 2 deletions examples/svg/svg-prerendered.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sprotty SVG Example</title>
<title>Sprotty Prerendered SVG / HTML Example</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
<link rel="stylesheet" href="css/page.css">
<!-- support Microsoft browsers -->
Expand All @@ -13,7 +13,7 @@
<div class="container">
<div class="row" id="sprotty-app" data-app="svg">
<div class="col-md-10">
<h1>Sprotty SVG Example</h1>
<h1>Sprotty Prerendered SVG / HTML Example</h1>
</div>
<div class="help col-md-2">
<a href='https://github.com/theia-ide/sprotty/wiki/Using-sprotty'>Help</a>
Expand Down
34 changes: 30 additions & 4 deletions src/lib/generic-views.ts → src/lib/generic-views.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2017-2018 TypeFox and others.
* Copyright (c) 2017-2020 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -14,12 +14,15 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

/** @jsx svg */
import { injectable } from "inversify";
import { svg } from 'snabbdom-jsx';
import virtualize from "snabbdom-virtualize/strings";
import { VNode } from "snabbdom/vnode";
import { IView, RenderingContext } from "../base/views/view";
import { setNamespace } from "../base/views/vnode-utils";
import { PreRenderedElement } from "./model";
import { injectable } from "inversify";
import { setNamespace, setAttr } from "../base/views/vnode-utils";
import { ForeignObjectElement, PreRenderedElement } from "./model";
import { getSubType } from "../base/model/smodel-utils";

@injectable()
export class PreRenderedView implements IView {
Expand All @@ -35,3 +38,26 @@ export class PreRenderedView implements IView {
}

}

/**
* An SVG `foreignObject` view with a namespace specified by the provided `ForeignObjectElement`.
* Note that `foreignObject` may not be supported by all browsers or SVG viewers.
*/
@injectable()
export class ForeignObjectView implements IView {
render(model: ForeignObjectElement, context: RenderingContext): VNode {
const foreignObjectContents = virtualize(model.code);
const node = <g>
<foreignObject requiredFeatures='http://www.w3.org/TR/SVG11/feature#Extensibility'
height={model.bounds.height} width={model.bounds.width} x={0} y={0}>
{foreignObjectContents}
</foreignObject>
{context.renderChildren(model)}
</g>;
setAttr(node, 'class', model.type);
const subType = getSubType(model);
if (subType) setAttr(node, 'class', subType);
setNamespace(foreignObjectContents, model.namespace);
return node;
}
}
47 changes: 44 additions & 3 deletions src/lib/model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2017-2018 TypeFox and others.
* Copyright (c) 2017-2020 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
Expand All @@ -15,8 +15,8 @@
********************************************************************************/

import { SModelRoot, SModelRootSchema, SChildElement, SModelElementSchema } from "../base/model/smodel";
import { Point, Dimension, ORIGIN_POINT, EMPTY_DIMENSION, Bounds } from "../utils/geometry";
import { BoundsAware, boundsFeature, Alignable, alignFeature } from "../features/bounds/model";
import { Point, Dimension, ORIGIN_POINT, EMPTY_DIMENSION, Bounds, isValidDimension, EMPTY_BOUNDS } from "../utils/geometry";
import { BoundsAware, boundsFeature, Alignable, alignFeature, isBoundsAware } from "../features/bounds/model";
import { Locateable, moveFeature } from "../features/move/model";
import { Selectable, selectFeature } from "../features/select/model";
import { SNode, SPort } from '../graph/sgraph';
Expand Down Expand Up @@ -136,3 +136,44 @@ export class ShapedPreRenderedElement extends PreRenderedElement implements Boun
}

}

/**
* A `foreignObject` element to be transferred to the DOM within the SVG.
*
* This can be useful to to benefit from e.g. HTML rendering features, such as line wrapping, inside of
* the SVG diagram. Note that `foreignObject` is not supported by all browsers and SVG viewers may not
* support rendering the `foreignObject` content.
*
* If no dimensions are specified in the schema element, this element will obtain the dimension of
* its parent to fill the entire available room. Thus, this element requires specified bounds itself
* or bounds to be available for its parent.
*/
export class ForeignObjectElement extends ShapedPreRenderedElement {
namespace: string;
get bounds(): Bounds {
if (isValidDimension(this.size)) {
return {
x: this.position.x,
y: this.position.y,
width: this.size.width,
height: this.size.height
};
} else if (isBoundsAware(this.parent)) {
return {
x: this.position.x,
y: this.position.y,
width: this.parent.bounds.width,
height: this.parent.bounds.height
};
}
return EMPTY_BOUNDS;
}
}

/**
* Serializable schema for ForeignObjectElement.
*/
export interface ForeignObjectElementSchema extends ShapedPreRenderedElementSchema {
/** The namespace to be assigned to the elements inside of the `foreignObject`. */
namespace: string
}

0 comments on commit 5cf9917

Please sign in to comment.