From a3251f2fdd55ac4cf30ad3dea78d9bff81ba1bca Mon Sep 17 00:00:00 2001 From: PMKuipers Date: Sat, 15 Jul 2023 22:00:27 +0200 Subject: [PATCH] Creating replacement for leaderline --- amd/src/simpleline.js | 143 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 amd/src/simpleline.js diff --git a/amd/src/simpleline.js b/amd/src/simpleline.js new file mode 100644 index 0000000..168035a --- /dev/null +++ b/amd/src/simpleline.js @@ -0,0 +1,143 @@ +/*eslint no-console: "off"*/ + +/** + * Copies defined properties in to, over from the from object. Does so recursively + * Ysed to copy user defined parameters onto a pre-existing object with defaults preset. + * @param {Object} to The object to copy to + * @param {Object} from The object tp copy from (but only the properties already named in "to") + */ +const specsCopy = (to, from) => { + for(const ix in to){ + if(from.hasOwnProperty(ix)){ + if( typeof to[ix] == "object" + && typeof from[ix] == "object") + { + if(Array.isArray(to[ix])){ + if(Array.isArray(from[ix])){ + to[ix] = Array.from(from[ix]); + } // else, skip... + } else { + specsCopy(to[ix], from[ix]); // recursive copy + } + } + else { + to[ix] = from[ix]; + } + } + } +}; + +/** + * Check if an element is a containing element and can thus be a parent for absolute positioning + * Which is the cas if the element has + * 1 A position value other than static (fixed, absolute, relative, or sticky). + * 2 A transform or perspective value other than none + * 3 A will-change value of transform or perspective + * 4 A filter value other than none or a will-change value of filter (only works on Firefox) + * 5 A contain value of layout, paint, strict or content (e.g. contain: paint;) + * 6 A container-type value other than normal + * 7 A backdrop-filter other than none (e.g. backdrop-filter: blur(10px);) + * @param {HTMLElement} el + * @returns {Boolean} + */ +const isContainingElement = (el) => { + const cssStyle = getComputedStyle(el); + return ["fixed","absolute","relative","sticky",].includes(cssStyle.position) + || cssStyle.transform !== "none" + || cssStyle.perspective !== "none" + || ["transform","perspective"].includes(cssStyle.willChange) + || cssStyle.filter !== "none" + || cssStyle.contain == "paint" + || cssStyle.backdropFilter !== "none"; +}; + +export class SimpleLine { + + constructor(start, end, specs){ + this.svg = null; + + // setup defaults + this.specs = { + container: null, + class: "", + colors: { + line : "currentcolor", + arrow: "currentcolor", + }, + anchors: { + // top, middle, bottom + // left, center, right + start: ["middle","right"], + end: ["middle", "left"], + } + }; + + specsCopy(this.specs,specs); + + // Validate start element + if(start instanceof HTMLElement) { + this.start = start; + } else if (typeof this.start === 'string' || this.start instanceof String) { + this.startSelector = start; + this.start = document.querySelector(start); + if(!(this.start instanceof HTMLElement)){ + console.error("Cannot find start element:",start); + return; + } + } else { + console.error("Start element not string or dom element",start); + } + + // Validate end element + if(end instanceof HTMLElement) { + this.end = end; + } else if (typeof this.end === 'string' || this.end instanceof String) { + this.endSelector = end; + this.end = document.querySelector(end); + if(!(this.end instanceof HTMLElement)){ + console.error("Cannot find end element:",end); + return; + } + } else { + console.error("End element not string or dom element",start); + } + + // Validate or determine container + if(this.specs.container){ + if(this.specs.container instanceof HTMLElement){ + this.container = this.specs.container; + } + else if (typeof this.specs.container === 'string' || this.specs.container instanceof String) { + this.container = document.querySelector(this.specs.container); + if(!(this.container instanceof HTMLElement)){ + console.warn("Cannot find specified container element:",this.specs.container); + this.specs.container = null; + } + } + else { + console.warn("Container specified is not a string or element:",this.specs.container); + this.specs.container = null; + } + } + if(!this.specs.container) { // if originally empty, or cleared + // find the first parent element of start that has position css attribute set (or body if none has it set) + const body = document.querySelector("body"); + let el = this.start.parentElement; + while( el !== body && !isContainingElement(el)){ + el = el.parentElement; + } + this.container = el; + } + + + } + + paintSvg(){ + const svg = document.createElement("svg"); + svg.attributes["viewBox"] = ""; + svg.attributes["width"] = ""; + svg.attributes["height"] = ""; + } + + +}