Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dia.CellView)!: separate alias and calc expression evaluation fro… #2335

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion demo/links/src/links.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@ var el1 = new joint.shapes.standard.Path({
attrs: {
body: {
fill: '#31d0c6',
d: 'M 0 calc(0.45 * h) calc(0.25 * w) calc(0.45 * h) calc(0.25 * w) calc(0.75 * h) calc(0.75 * w) calc(0.75 * h) calc(0.75 * w) 0 calc(w) 0 calc(w) calc(h) 0 calc(h) z'
d: 'M 0 calc(0.45 * h) calc(0.25 * w) calc(0.45 * h) calc(0.25 * w) calc(0.75 * h) calc(0.75 * w) calc(0.75 * h) calc(0.75 * w) 0 calc(w) 0 calc(w) calc(h) 0 calc(h) z',
refD: null
}
}
});
Expand Down
5 changes: 4 additions & 1 deletion src/config/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ export const config = {
defaultTheme: 'default',
// The maximum delay required for two consecutive touchend events to be interpreted
// as a double-tap.
doubleTapInterval: 300
doubleTapInterval: 300,
// Should be the camel case attributes converted to dash case attributes.
// e.g. `strokeWidth` -> `stroke-width`
supportCamelCaseAttributes: true,
};
42 changes: 30 additions & 12 deletions src/dia/CellView.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { Point, Rect } from '../g/index.mjs';
import V from '../V/index.mjs';
import $ from 'jquery';
import { HighlighterView } from './HighlighterView.mjs';
import { aliases } from './attributes/aliases.mjs';
import { evalCalcAttributes } from './attributes/calcAttributes.mjs';

const HighlightingTypes = {
DEFAULT: 'default',
Expand Down Expand Up @@ -542,12 +544,15 @@ export const CellView = View.extend({
var attrName, attrVal, def, i, n;
var normalAttrs, setAttrs, positionAttrs, offsetAttrs;
var relatives = [];
const rawAttrs = {};
// divide the attributes between normal and special
for (attrName in attrs) {
if (!attrs.hasOwnProperty(attrName)) continue;
attrVal = attrs[attrName];
attrName = this.translateAttributeName(attrName);
rawAttrs[attrName] = attrVal;
def = this.getAttributeDefinition(attrName);
if (def && (!isFunction(def.qualify) || def.qualify.call(this, attrVal, node, attrs, this))) {
if (def && (!isFunction(def.qualify) || def.qualify.call(this, attrVal, node, rawAttrs, this))) {
if (isString(def.set)) {
normalAttrs || (normalAttrs = {});
normalAttrs[def.set] = attrVal;
Expand All @@ -557,7 +562,7 @@ export const CellView = View.extend({
}
} else {
normalAttrs || (normalAttrs = {});
normalAttrs[toKebabCase(attrName)] = attrVal;
normalAttrs[attrName] = attrVal;
}
}

Expand All @@ -582,32 +587,45 @@ export const CellView = View.extend({
}

return {
raw: attrs,
raw: rawAttrs,
normal: normalAttrs,
set: setAttrs,
position: positionAttrs,
offset: offsetAttrs
};
},

translateAttributeName: function(name) {
if (name in aliases) {
return aliases[name];
}
if (config.supportCamelCaseAttributes) {
return toKebabCase(name);
}
return name;
},

updateRelativeAttributes: function(node, attrs, refBBox, opt) {

opt || (opt = {});

var attrName, attrVal, def;
var rawAttrs = attrs.raw || {};
var evalAttrs = evalCalcAttributes(attrs.raw || {}, refBBox);
var nodeAttrs = attrs.normal || {};
for (const nodeAttrName in nodeAttrs) {
nodeAttrs[nodeAttrName] = evalAttrs[nodeAttrName];
}
var setAttrs = attrs.set;
var positionAttrs = attrs.position;
var offsetAttrs = attrs.offset;

for (attrName in setAttrs) {
attrVal = setAttrs[attrName];
attrVal = evalAttrs[attrName];
def = this.getAttributeDefinition(attrName);
// SET - set function should return attributes to be set on the node,
// which will affect the node dimensions based on the reference bounding
// box. e.g. `width`, `height`, `d`, `rx`, `ry`, `points
var setResult = def.set.call(this, attrVal, refBBox.clone(), node, rawAttrs, this);
var setResult = def.set.call(this, attrVal, refBBox.clone(), node, evalAttrs, this);
if (isObject(setResult)) {
assign(nodeAttrs, setResult);
} else if (setResult !== undefined) {
Expand Down Expand Up @@ -643,13 +661,13 @@ export const CellView = View.extend({

var positioned = false;
for (attrName in positionAttrs) {
attrVal = positionAttrs[attrName];
attrVal = evalAttrs[attrName];
def = this.getAttributeDefinition(attrName);
// POSITION - position function should return a point from the
// reference bounding box. The default position of the node is x:0, y:0 of
// the reference bounding box or could be further specify by some
// SVG attributes e.g. `x`, `y`
translation = def.position.call(this, attrVal, refBBox.clone(), node, rawAttrs, this);
translation = def.position.call(this, attrVal, refBBox.clone(), node, evalAttrs, this);
if (translation) {
nodePosition.offset(Point(translation).scale(sx, sy));
positioned || (positioned = true);
Expand All @@ -667,12 +685,12 @@ export const CellView = View.extend({
if (nodeBoundingRect.width > 0 && nodeBoundingRect.height > 0) {
var nodeBBox = V.transformRect(nodeBoundingRect, nodeMatrix).scale(1 / sx, 1 / sy);
for (attrName in offsetAttrs) {
attrVal = offsetAttrs[attrName];
attrVal = evalAttrs[attrName];
def = this.getAttributeDefinition(attrName);
// OFFSET - offset function should return a point from the element
// bounding box. The default offset point is x:0, y:0 (origin) or could be further
// specify with some SVG attributes e.g. `text-anchor`, `cx`, `cy`
translation = def.offset.call(this, attrVal, nodeBBox, node, rawAttrs, this);
translation = def.offset.call(this, attrVal, nodeBBox, node, evalAttrs, this);
if (translation) {
nodePosition.offset(Point(translation).scale(sx, sy));
offseted || (offseted = true);
Expand Down Expand Up @@ -872,9 +890,9 @@ export const CellView = View.extend({
node = nodeData.node;
processedAttrs = this.processNodeAttributes(node, nodeAttrs);

if (!processedAttrs.set && !processedAttrs.position && !processedAttrs.offset) {
if (!processedAttrs.set && !processedAttrs.position && !processedAttrs.offset && !processedAttrs.raw.ref) {
// Set all the normal attributes right on the SVG/HTML element.
this.setNodeAttributes(node, processedAttrs.normal);
this.setNodeAttributes(node, evalCalcAttributes(processedAttrs.normal, opt.rootBBox));

} else {

Expand Down
17 changes: 17 additions & 0 deletions src/dia/attributes/aliases.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const aliases = {
xlinkHref: 'xlink:href',
xlinkShow: 'xlink:show',
xlinkRole: 'xlink:role',
xlinkType: 'xlink:type',
xlinkArcrole: 'xlink:arcrole',
xlinkTitle: 'xlink:title',
xlinkActuate: 'xlink:actuate',
xmlSpace: 'xml:space',
xmlLang: 'xml:lang',
xmlBase: 'xml:base',
preserveAspectRatio: 'preserveAspectRatio',
requiredExtensions: 'requiredExtensions',
requiredFeatures: 'requiredFeatures',
systemLanguage: 'systemLanguage',
externalResourcesRequired: 'externalResourcesRequired',
};
56 changes: 56 additions & 0 deletions src/dia/attributes/calcAttributes.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { isCalcAttribute, evalCalcAttribute } from './calc.mjs';

const calcAttributesList = [
'transform',
'x',
'y',
'cx',
'cy',
'x1',
'y1',
'x2',
'y2',
'points',
'd',
'r',
'rx',
'ry',
'width',
'height',
'stroke-width',
'font-size',
];
const positiveValueList = [
'r',
'rx',
'ry',
'width',
'height',
'stroke-width',
'font-size',
];

const calcAttributes = calcAttributesList.reduce((acc, attrName) => {
acc[attrName] = true;
return acc;
}, {});

const positiveValueAttributes = positiveValueList.reduce((acc, attrName) => {
acc[attrName] = true;
return acc;
}, {});

export function evalCalcAttributes(attrs, refBBox) {
for (let attrName in attrs) {
if (!attrs.hasOwnProperty(attrName)) continue;
let value = attrs[attrName];
if (attrName in calcAttributes && isCalcAttribute(value)) {
value = evalCalcAttribute(value, refBBox);
if (attrName in positiveValueAttributes) {
value = Math.max(0, value);
}
attrs[attrName] = value;
}
}
return attrs;
}
Loading