@sfgrp/svg-radial-menu
Advanced tools
Comparing version 1.0.4 to 1.0.5
@@ -1,1 +0,1 @@ | ||
class SVG{constructor(t){this.SVGElement=this.createSVGElement("svg",t)}createSVGElement(t,e={}){t=document.createElementNS("http://www.w3.org/2000/svg",t);return this.SetSVGAttributes(t,e),t}SetSVGAttributes(t,e){for(var i in e)t.setAttribute(i,`${e[i]}`)}parseAttributes(t){return Object.fromEntries(Object.entries(t).filter(([,t])=>t).map(([t,e])=>[[t.replace(/\B(?:([A-Z])(?=[a-z]))|(?:(?<=[a-z0-9])([A-Z]))/g,"-$1$2").toLowerCase()],e]))}createSVGCircle(t,e,i,s={}){var r=this.createSVGElement("circle",s);return this.SetSVGAttributes(r,Object.assign({cx:t,cy:e,r:i},s)),r}createSVGImage(t,e,i,s,r){const n=document.createElementNS("http://www.w3.org/2000/svg","image");return n.setAttribute("x",`${t}px`),n.setAttribute("y",`${e}px`),n.setAttribute("width",`${i}px`),n.setAttribute("height",`${s}px`),n.setAttribute("href",r),n}createSVGLink(t,e){const i=document.createElementNS("http://www.w3.org/2000/svg","a");return i.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",e),i.append(t),i}createSVGText(s,t,e,r={}){const i=e.split(" "),n=parseInt(`${r["font-size"]}`,10),h=1===i.length?n/2:n/2*-i.length+n;e=i.map((t,e)=>{const i=this.createSVGElement("tspan",r);e=e?n:h;return i.setAttribute("dy",`${e}px`),i.setAttribute("x",`${s}px`),i.removeAttribute("y"),i.textContent=t,i});return this.createSVGGroup(e,"text",{x:s,y:t,dy:0})}createSVGGroup(t,e="g",i={}){const s=this.createSVGElement(e,i);return t.forEach(t=>{s.appendChild(t)}),s}describeArc(t,e,i,s,r,n){const h=this.polarToCartesian(t,e,i,n),a=this.polarToCartesian(t,e,i,r),o=this.polarToCartesian(t,e,i+s,n),l=this.polarToCartesian(t,e,i+s,r),c=n-r<=180?"0":"1";return["M",o.x,o.y,"A",i+s,i+s,0,c,0,l.x,l.y,"L",a.x,a.y,"A",i,i,0,c,1,h.x,h.y,"L",o.x,o.y,"Z"].join(" ")}polarToCartesian(t,e,i,s){s=(s-90)*Math.PI/180;return{x:t+i*Math.cos(s),y:e+i*Math.sin(s)}}}class Segment extends SVG{constructor(t,e,i,s,r,n,h){super(h),this.backgroundColor="#FFFFFF",this.margin=0,this.textColor="#FFFFFF",this.innerPosition=2;var{sliceSize:a,margin:o}=h;this.options=h,this.slice=t,this._name=t.name,this.size=t.size||a,this.startFrom=s,this.radiusStart=r,this.radiusEnd=r+n,this.x=e,this.y=i,this.margin=o||this.margin,this.SVGAttributes=this.parseAttributes(t.svgAttributes||{}),this.defaultSVGAttributes=this.parseAttributes(h.svgAttributes||{}),this.innerPosition=t.innerPosition||h.innerPosition||this.innerPosition,360<=this.radiusEnd-this.radiusStart&&(this.radiusEnd=359.999,this.margin=0),this.SVGElement=this.createSlice(this.x,this.y,this.startFrom,this.size,this.radiusStart,this.radiusEnd,this.options)}toSVG(){return this.SVGElement}createSlice(t,e,i,s,r,n,h){var a=this.slice;const o=[];var l=s/this.innerPosition+i,c=(n-r)/2,e=this.polarToCartesian(t,e,this.margin,r+c),c=this.polarToCartesian(e.x,e.y,l,r+c),n=this.describeArc(e.x,e.y,i,s,r,n),n=this.createSVGElement("path",Object.assign({},this.getAttributes,{d:n}));return o.push(n),a.label&&(n=(null===(n=null==a?void 0:a.icon)||void 0===n?void 0:n.height)||0,o.push(this.createSVGText(c.x,c.y+n/2,a.label,Object.assign({},this.defaultSVGAttributes,this.SVGAttributes,{fill:this.SVGAttributes.color||this.defaultSVGAttributes.color})))),a.icon&&o.push(this.addIcon(a.icon,c)),c=this.createSVGGroup(o),a.link?this.createSVGLink(c,a.link):c}get name(){return this._name}get fontSize(){return parseInt(`${this.getAttributes["font-size"]||11}`,10)}get getAttributes(){return Object.assign({},this.defaultSVGAttributes,this.SVGAttributes)}addIcon(t,{x:e,y:i}){var{width:s,height:r,url:t}=t,i={x:e-s/2,y:this.slice.label?i-r/2-this.getTextSize(this.slice.label):i-r/2};return this.createSVGImage(i.x,i.y,s,r,t)}getTextSize(t){return t.split(" ").length*this.fontSize/2}}class MiddleButton extends SVG{constructor(t,e,i,s){super(s),this.backgroundColor="#FFFFFF",this.sliceMargin=4,this.textColor="#FFFFFF",this.options=s,this.middleButton=t,this.radius=t.radius||s.centerSize,this.x=e,this.y=i,this._name=this.middleButton.name,this.SVGAttributes=this.parseAttributes(t.svgAttributes||{}),this.defaultSVGAttributes=this.parseAttributes(s.svgAttributes||{}),this.SVGElement=this.createMiddleButton(this.x,this.y,this.radius,s)}toSVG(){return this.SVGElement}get name(){return this._name}get getAttributes(){return Object.assign({},this.defaultSVGAttributes,this.SVGAttributes)}createMiddleButton(t,e,i,s){var r=this.middleButton;const n=[];i=this.createSVGCircle(t,e,i,{fill:this.SVGAttributes.fill,color:this.textColor});return n.push(i),r.label&&n.push(this.createSVGText(t,e,r.label,Object.assign({},this.defaultSVGAttributes,this.SVGAttributes,{fill:this.SVGAttributes.color}))),r.icon&&n.push(this.addIcon(r.icon,{x:t,y:e})),e=this.createSVGGroup(n),r.link?this.createSVGLink(e,r.link):e}addIcon(t,{x:e,y:i}){var{width:s,height:r,url:n}=t,t=parseInt(this.getAttributes["font-size"].toString(),10),i={x:e-s/2,y:this.middleButton.label?i-r-t:i-r/2};return this.createSVGImage(i.x,i.y,s,r,n)}}class EventEmitter{constructor(){this.events={}}on(t,e){return"object"!=typeof this.events[t]&&(this.events[t]=[]),this.events[t].push(e),()=>this.removeListener(t,e)}removeListener(t,e){"object"!=typeof this.events[t]||-1<(e=this.events[t].indexOf(e))&&this.events[t].splice(e,1)}removeAllListeners(){Object.keys(this.events).forEach(t=>this.events[t].splice(0,this.events[t].length))}emit(t,...e){"object"==typeof this.events[t]&&[...this.events[t]].forEach(t=>t.apply(this,e))}once(t,e){const i=this.on(t,(...t)=>{i(),e.apply(this,t)});return i}}class RadialMenu extends EventEmitter{constructor(t,e){super(),this.innerPosition=2,this.SVGSlices=[],this.margin=0;var{centerSize:i,width:s,height:r,slices:n,sliceSize:h,middleButton:a,margin:o,css:l,innerPosition:c}=e;this.SVGObject=new SVG(Object.assign({width:`${s}px`,height:`${r}px`},l||{})),this.SVGElement=this.SVGObject.SVGElement,this.innerPosition=c||this.innerPosition,this.parentElement=t,this.options=e,this.width=s,this.height=r,this.slices=n,this.sliceSize=h,this.centerSize=i,this.middleButton=a||{},this.margin=o||this.margin,this.SVGAttributes=e.svgAttributes||{},this.generateMenu()}generateMenu(){let t;this.drawLevel(this.slices),this.SVGSlices.forEach(t=>{this.addEvents(t),this.SVGElement.appendChild(t.toSVG())}),this.middleButton&&(t=new MiddleButton(this.middleButton,this.width/2,this.height/2,this.options),this.addEvents(t),this.SVGElement.appendChild(t.toSVG())),this.parentElement.innerHTML="",this.parentElement.appendChild(this.SVGElement)}drawLevel(t,r=this.centerSize,n=0,e=360){const h=[];var i=t.filter(({radius:t})=>t).length;const a=(e-t.map(({radius:t})=>t||0).reduce((t,e)=>t+e,0)-n)/(t.length-i),o=this.width/2,l=this.height/2;t.forEach(t=>{var e=r,i=t.radius||a,s=t.slices;h.push(new Segment(t,o,l,e,n,i,this.options)),e=e+((null==t?void 0:t.size)||this.sliceSize)+this.margin,s&&this.drawLevel(s,e,n,n+i),n+=i}),this.SVGSlices=this.SVGSlices.concat([],h)}addEvents(e){const t=e.toSVG(),{name:i}=e;t.addEventListener("click",t=>{this.emit("click",{event:t,segmentObject:e,name:i})}),t.addEventListener("dbclick",t=>{this.emit("dbclick",{event:t,segmentObject:e,name:i})}),t.addEventListener("contextmenu",t=>{this.emit("contextmenu",{event:t,segmentObject:e,name:i})})}}export default RadialMenu; | ||
class SVG{constructor(t){this.SVGElement=this.createSVGElement("svg",t)}createSVGElement(t,e={}){t=document.createElementNS("http://www.w3.org/2000/svg",t);return this.SetSVGAttributes(t,e),t}SetSVGAttributes(t,e){for(var i in e)t.setAttribute(i,`${e[i]}`)}parseAttributes(t){return Object.fromEntries(Object.entries(t).filter(([,t])=>t).map(([t,e])=>[[t.replace(/\B(?:([A-Z])(?=[a-z]))|(?:(?<=[a-z0-9])([A-Z]))/g,"-$1$2").toLowerCase()],e]))}createSVGCircle(t,e,i,s={}){var r=this.createSVGElement("circle",s);return this.SetSVGAttributes(r,Object.assign({cx:t,cy:e,r:i},s)),r}createSVGImage(t,e,i,s,r){const n=document.createElementNS("http://www.w3.org/2000/svg","image");return n.setAttribute("x",`${t}px`),n.setAttribute("y",`${e}px`),n.setAttribute("width",`${i}px`),n.setAttribute("height",`${s}px`),n.setAttribute("href",r),n}createSVGLink(t,e){const i=document.createElementNS("http://www.w3.org/2000/svg","a");return i.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",e),i.append(t),i}createSVGText(s,t,e,r={}){const i=e.split(" "),n=parseInt(`${r["font-size"]}`,10),h=1===i.length?n/2:n/2*-i.length+n;e=i.map((t,e)=>{const i=this.createSVGElement("tspan",r);e=e?n:h;return i.setAttribute("dy",`${e}px`),i.setAttribute("x",`${s}px`),i.removeAttribute("y"),i.textContent=t,i});return this.createSVGGroup(e,"text",{x:s,y:t,dy:0})}createSVGGroup(t,e="g",i={}){const s=this.createSVGElement(e,i);return t.forEach(t=>{s.appendChild(t)}),s}describeArc(t,e,i,s,r,n){const h=this.polarToCartesian(t,e,i,n),a=this.polarToCartesian(t,e,i,r),o=this.polarToCartesian(t,e,i+s,n),l=this.polarToCartesian(t,e,i+s,r),c=n-r<=180?"0":"1";return["M",o.x,o.y,"A",i+s,i+s,0,c,0,l.x,l.y,"L",a.x,a.y,"A",i,i,0,c,1,h.x,h.y,"L",o.x,o.y,"Z"].join(" ")}polarToCartesian(t,e,i,s){s=s*Math.PI/180;return{x:t+i*Math.cos(s),y:e+i*Math.sin(s)}}}class Segment extends SVG{constructor(t,e,i,s,r,n,h){super(h),this.backgroundColor="#FFFFFF",this.margin=0,this.textColor="#FFFFFF",this.innerPosition=2;var{sliceSize:a,margin:o}=h;this.options=h,this.slice=t,this._name=t.name,this.size=t.size||a,this.startFrom=s,this.radiusStart=r,this.radiusEnd=r+n,this.x=e,this.y=i,this.margin=o||this.margin,this.SVGAttributes=this.parseAttributes(t.svgAttributes||{}),this.defaultSVGAttributes=this.parseAttributes(h.svgAttributes||{}),this.innerPosition=t.innerPosition||h.innerPosition||this.innerPosition,360<=this.radiusEnd-this.radiusStart&&(this.radiusEnd=359.999,this.margin=0),this.SVGElement=this.createSlice(this.x,this.y,this.startFrom,this.size,this.radiusStart,this.radiusEnd,this.options)}toSVG(){return this.SVGElement}createSlice(t,e,i,s,r,n,h){var a=this.slice;const o=[];var l=s/this.innerPosition+i,c=(n-r)/2,e=this.polarToCartesian(t,e,this.margin,r+c),c=this.polarToCartesian(e.x,e.y,l,r+c),n=this.describeArc(e.x,e.y,i,s,r,n),n=this.createSVGElement("path",Object.assign({},this.getAttributes,{d:n}));return o.push(n),a.label&&(n=(null===(n=null==a?void 0:a.icon)||void 0===n?void 0:n.height)||0,o.push(this.createSVGText(c.x,c.y+n/2,a.label,Object.assign({},this.defaultSVGAttributes,this.SVGAttributes,{fill:this.SVGAttributes.color||this.defaultSVGAttributes.color})))),a.icon&&o.push(this.addIcon(a.icon,c)),c=this.createSVGGroup(o),a.link?this.createSVGLink(c,a.link):c}get name(){return this._name}get fontSize(){return parseInt(`${this.getAttributes["font-size"]||11}`,10)}get getAttributes(){return Object.assign({},this.defaultSVGAttributes,this.SVGAttributes)}addIcon(t,{x:e,y:i}){var{width:s,height:r,url:t}=t,i={x:e-s/2,y:this.slice.label?i-r/2-this.getTextSize(this.slice.label):i-r/2};return this.createSVGImage(i.x,i.y,s,r,t)}getTextSize(t){return t.split(" ").length*this.fontSize/2}}class MiddleButton extends SVG{constructor(t,e,i,s){super(s),this.backgroundColor="#FFFFFF",this.sliceMargin=4,this.textColor="#FFFFFF",this.options=s,this.middleButton=t,this.radius=t.radius||s.centerSize,this.x=e,this.y=i,this._name=this.middleButton.name,this.SVGAttributes=this.parseAttributes(t.svgAttributes||{}),this.defaultSVGAttributes=this.parseAttributes(s.svgAttributes||{}),this.SVGElement=this.createMiddleButton(this.x,this.y,this.radius,s)}toSVG(){return this.SVGElement}get name(){return this._name}get getAttributes(){return Object.assign({},this.defaultSVGAttributes,this.SVGAttributes)}createMiddleButton(t,e,i,s){var r=this.middleButton;const n=[];i=this.createSVGCircle(t,e,i,{fill:this.SVGAttributes.fill,color:this.textColor});return n.push(i),r.label&&n.push(this.createSVGText(t,e,r.label,Object.assign({},this.defaultSVGAttributes,this.SVGAttributes,{fill:this.SVGAttributes.color}))),r.icon&&n.push(this.addIcon(r.icon,{x:t,y:e})),e=this.createSVGGroup(n),r.link?this.createSVGLink(e,r.link):e}addIcon(t,{x:e,y:i}){var{width:s,height:r,url:n}=t,t=parseInt(this.getAttributes["font-size"].toString(),10),i={x:e-s/2,y:this.middleButton.label?i-r-t:i-r/2};return this.createSVGImage(i.x,i.y,s,r,n)}}class EventEmitter{constructor(){this.events={}}on(t,e){return"object"!=typeof this.events[t]&&(this.events[t]=[]),this.events[t].push(e),()=>this.removeListener(t,e)}removeListener(t,e){"object"!=typeof this.events[t]||-1<(e=this.events[t].indexOf(e))&&this.events[t].splice(e,1)}removeAllListeners(){Object.keys(this.events).forEach(t=>this.events[t].splice(0,this.events[t].length))}emit(t,...e){"object"==typeof this.events[t]&&[...this.events[t]].forEach(t=>t.apply(this,e))}once(t,e){const i=this.on(t,(...t)=>{i(),e.apply(this,t)});return i}}class RadialMenu extends EventEmitter{constructor(t,e){super(),this.innerPosition=2,this.SVGSlices=[],this.margin=0;var{centerSize:i,width:s,height:r,slices:n,sliceSize:h,middleButton:a,margin:o,css:l,innerPosition:c}=e;this.SVGObject=new SVG(Object.assign({width:`${s}px`,height:`${r}px`},l||{})),this.SVGElement=this.SVGObject.SVGElement,this.innerPosition=c||this.innerPosition,this.parentElement=t,this.options=e,this.width=s,this.height=r,this.slices=n,this.sliceSize=h,this.centerSize=i,this.middleButton=a||{},this.margin=o||this.margin,this.SVGAttributes=e.svgAttributes||{},this.generateMenu()}generateMenu(){let t;this.drawLevel(this.slices),this.SVGSlices.forEach(t=>{this.addEvents(t),this.SVGElement.appendChild(t.toSVG())}),this.middleButton&&(t=new MiddleButton(this.middleButton,this.width/2,this.height/2,this.options),this.addEvents(t),this.SVGElement.appendChild(t.toSVG())),this.parentElement.innerHTML="",this.parentElement.appendChild(this.SVGElement)}drawLevel(t,r=this.centerSize,n=0,e=360){const h=[];var i=t.filter(({radius:t})=>t).length;const a=(e-t.map(({radius:t})=>t||0).reduce((t,e)=>t+e,0)-n)/(t.length-i),o=this.width/2,l=this.height/2;t.forEach(t=>{var e=r,i=t.radius||a,s=t.slices;h.push(new Segment(t,o,l,e,n,i,this.options)),e=e+((null==t?void 0:t.size)||this.sliceSize)+this.margin,s&&this.drawLevel(s,e,n,n+i),n+=i}),this.SVGSlices=this.SVGSlices.concat([],h)}addEvents(e){const t=e.toSVG(),{name:i}=e;t.addEventListener("click",t=>{this.emit("click",{event:t,segmentObject:e,name:i})}),t.addEventListener("dbclick",t=>{this.emit("dbclick",{event:t,segmentObject:e,name:i})}),t.addEventListener("contextmenu",t=>{this.emit("contextmenu",{event:t,segmentObject:e,name:i})})}}export default RadialMenu;//# sourceMappingURL=svg-radial-menu.esm.js.map |
{ | ||
"name": "@sfgrp/svg-radial-menu", | ||
"version": "1.0.4", | ||
"version": "1.0.5", | ||
"description": "Library to create radial menus", | ||
"main": "dist/svg-radial-menu.esm.js", | ||
"module": "dist/svg-radial-menu.esm.js", | ||
"types": "dist/index.d.ts", | ||
"private": false, | ||
@@ -8,0 +9,0 @@ "keywords": [ |
@@ -20,11 +20,3 @@ # SVG Radial Menu | ||
To create a production build: | ||
```sh | ||
npm run build:library | ||
``` | ||
Navigate to `http://localhost:8080/` in your browser. | ||
## Installation | ||
@@ -68,3 +60,4 @@ | ||
class: 'radial-menu' | ||
} | ||
}, | ||
slices: [{ | ||
@@ -91,3 +84,15 @@ label: 'Example', | ||
] | ||
] | ||
], | ||
middleButton: { // Middle button | ||
name: center, | ||
radius: 28, | ||
name: 'middle', | ||
svgAttributes: { | ||
... | ||
} | ||
icon: { | ||
... | ||
} | ||
}, | ||
} | ||
@@ -99,2 +104,12 @@ ``` | ||
#### click, dbclick, contextmenu | ||
```javascript | ||
import RadialMenu from '@sfg/svg-radial-menu' | ||
const element = document.querySelector('#svg-menu-container') | ||
const myMenu.on('click', function (event) { | ||
console.log('Hey, ) | ||
}) | ||
``` | ||
Events are triggered when a slice or middle button is clicked providing the following data: | ||
@@ -101,0 +116,0 @@ |
@@ -11,3 +11,4 @@ import typescript from '@rollup/plugin-typescript' | ||
format: 'esm', | ||
compact: true | ||
compact: true, | ||
sourcemap: true | ||
} | ||
@@ -14,0 +15,0 @@ ], |
@@ -40,3 +40,3 @@ import "./styles.css"; | ||
{ | ||
label: '6 a', | ||
label: '6', | ||
name: 'alert', | ||
@@ -43,0 +43,0 @@ size: 26, |
@@ -1,2 +0,2 @@ | ||
import { Slice, SliceIcon, CircleButton, RadialMenuOptions, SVGAttribute } from './types' | ||
import { Slice, SliceIcon, CircleButton, RadialMenuOptions, SVGAttribute } from './types/types' | ||
import { SVG } from './utils/svg' | ||
@@ -3,0 +3,0 @@ |
@@ -10,3 +10,3 @@ import { SVG } from './utils/svg' | ||
SVGAttribute | ||
} from './types' | ||
} from './types/types' | ||
@@ -13,0 +13,0 @@ export default class RadialMenu extends EventEmitter { |
@@ -1,2 +0,2 @@ | ||
import { Slice, SliceIcon, RadialMenuOptions, SVGAttribute } from './types' | ||
import { Slice, SliceIcon, RadialMenuOptions, SVGAttribute } from './types/types' | ||
import { SVG } from './utils/svg' | ||
@@ -3,0 +3,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { SVGAttribute } from '../types' | ||
import { SVGAttribute } from '../types/types' | ||
export class SVG { | ||
@@ -119,3 +119,3 @@ | ||
public polarToCartesian(centerX: number, centerY: number, radius: number, angleInDegrees: number) { | ||
const angleInRadians = (angleInDegrees-90) * Math.PI / 180.0 | ||
const angleInRadians = (angleInDegrees) * Math.PI / 180.0 | ||
@@ -122,0 +122,0 @@ return { |
@@ -12,2 +12,3 @@ { | ||
"allowJs": true, | ||
"declaration": true, | ||
"lib": ["esnext", "dom"] | ||
@@ -14,0 +15,0 @@ }, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
44217
17
652
120