Skip to content

Commit 1c11339

Browse files
Update liqglass.js
Added Svg Filters / 2 new filters
1 parent 4b9c806 commit 1c11339

File tree

1 file changed

+198
-30
lines changed

1 file changed

+198
-30
lines changed

src/liqglass.js

Lines changed: 198 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
* LiqGlass - Beautiful Glass Morphism Library
33
* A comprehensive JavaScript library for creating stunning glass effects
44
*
5-
* @version 1.0.0
6-
* @author LiqGlass Library
7-
* @license MIT
5+
* @version 1.2.0
86
*/
97

108
(function (global, factory) {
@@ -36,6 +34,8 @@
3634
* @property {boolean} [hoverEffect=false] - Enable hover effects
3735
* @property {string} [element='div'] - HTML element type to create
3836
* @property {string} [className=''] - CSS class name to apply
37+
* @property {string} [svgFilter] - SVG filter markup to inject
38+
* @property {string} [svgFilterId] - ID of the SVG filter to apply
3939
*/
4040

4141
/**
@@ -62,6 +62,8 @@
6262
this.colorPresets = new Map();
6363
this.generatedStyles = new Set();
6464
this.styleElement = null;
65+
this.svgFilters = new Map();
66+
this.elementFilterMap = new WeakMap();
6567

6668
this.initializeDefaultPresets();
6769
this.initializeColorPresets();
@@ -150,6 +152,34 @@
150152
gradientFrom: 'rgba(255,255,255,0.3)',
151153
gradientTo: 'rgba(255,255,255,0.1)'
152154
});
155+
156+
this.presets.set('refraction', {
157+
blur: 10,
158+
opacity: 0.08,
159+
borderRadius: 20,
160+
borderWidth: 1,
161+
borderOpacity: 0.15,
162+
shadowIntensity: 'medium',
163+
gradient: true,
164+
gradientFrom: 'rgba(255,255,255,0.15)',
165+
gradientTo: 'rgba(255,255,255,0.05)',
166+
svgFilter: '<svg style="display: none"><filter id="lg-dist" x="0%" y="0%" width="100%" height="100%"><feTurbulence type="fractalNoise" baseFrequency="0.008 0.008" numOctaves="2" seed="92" result="noise" /><feGaussianBlur in="noise" stdDeviation="2" result="blurred" /><feDisplacementMap in="SourceGraphic" in2="blurred" scale="70" xChannelSelector="R" yChannelSelector="G" /></filter></svg>',
167+
svgFilterId: 'lg-dist'
168+
});
169+
170+
this.presets.set('distortion', {
171+
blur: 8,
172+
opacity: 0.12,
173+
borderRadius: 16,
174+
borderWidth: 1,
175+
borderOpacity: 0.2,
176+
shadowIntensity: 'heavy',
177+
gradient: true,
178+
gradientFrom: 'rgba(255,255,255,0.2)',
179+
gradientTo: 'rgba(255,255,255,0.08)',
180+
svgFilter: '<svg style="display: none"><filter id="glass-distortion" x="0%" y="0%" width="100%" height="100%" filterUnits="objectBoundingBox"><feTurbulence type="fractalNoise" baseFrequency="0.01 0.01" numOctaves="1" seed="5" result="turbulence" /><feComponentTransfer in="turbulence" result="mapped"><feFuncR type="gamma" amplitude="1" exponent="10" offset="0.5" /><feFuncG type="gamma" amplitude="0" exponent="1" offset="0" /><feFuncB type="gamma" amplitude="0" exponent="1" offset="0.5" /></feComponentTransfer><feGaussianBlur in="turbulence" stdDeviation="3" result="softMap" /><feSpecularLighting in="softMap" surfaceScale="5" specularConstant="1" specularExponent="100" lighting-color="white" result="specLight"><fePointLight x="-200" y="-200" z="300" /></feSpecularLighting><feComposite in="specLight" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litImage" /><feDisplacementMap in="SourceGraphic" in2="softMap" scale="150" xChannelSelector="R" yChannelSelector="G" /></filter></svg>',
181+
svgFilterId: 'glass-distortion'
182+
});
153183
}
154184

155185
/**
@@ -278,6 +308,11 @@
278308

279309
Object.assign(element.style, styles);
280310

311+
// Handle SVG filters
312+
if (config.svgFilter && config.svgFilterId) {
313+
this.applySVGFilter(element, config.svgFilter, config.svgFilterId);
314+
}
315+
281316
// Add base class
282317
element.classList.add('liqglass-base');
283318

@@ -291,6 +326,102 @@
291326
}
292327
}
293328

329+
/**
330+
* Apply SVG filter to an element
331+
* @param {HTMLElement} element - Target element
332+
* @param {string} svgFilter - SVG filter markup
333+
* @param {string} filterId - Filter ID
334+
* @private
335+
*/
336+
applySVGFilter(element, svgFilter, filterId) {
337+
if (typeof document === 'undefined') return;
338+
339+
// Check if filter already exists
340+
if (!this.svgFilters.has(filterId)) {
341+
// Create SVG element
342+
const svgContainer = document.createElement('div');
343+
svgContainer.innerHTML = svgFilter;
344+
const svgElement = svgContainer.firstElementChild;
345+
346+
if (svgElement) {
347+
document.body.appendChild(svgElement);
348+
this.svgFilters.set(filterId, svgElement);
349+
}
350+
}
351+
352+
// Track element for cleanup
353+
this.elementFilterMap.set(element, filterId);
354+
355+
// Set up cleanup observer
356+
this.setupElementCleanup(element, filterId);
357+
}
358+
359+
/**
360+
* Setup cleanup observer for element removal
361+
* @param {HTMLElement} element - Element to observe
362+
* @param {string} filterId - Filter ID
363+
* @private
364+
*/
365+
setupElementCleanup(element, filterId) {
366+
if (typeof window === 'undefined' || !window.MutationObserver) return;
367+
368+
const observer = new MutationObserver((mutations) => {
369+
for (const mutation of mutations) {
370+
if (mutation.type === 'childList') {
371+
for (const removedNode of Array.from(mutation.removedNodes)) {
372+
if (removedNode === element || (removedNode.contains && removedNode.contains(element))) {
373+
this.cleanupSVGFilter(filterId);
374+
observer.disconnect();
375+
return;
376+
}
377+
}
378+
}
379+
}
380+
});
381+
382+
observer.observe(document.body, {
383+
childList: true,
384+
subtree: true
385+
});
386+
}
387+
388+
/**
389+
* Cleanup SVG filter when no longer needed
390+
* @param {string} filterId - Filter ID
391+
* @private
392+
*/
393+
cleanupSVGFilter(filterId) {
394+
const svgElement = this.svgFilters.get(filterId);
395+
if (svgElement && svgElement.parentNode) {
396+
// Check if any other elements are using this filter
397+
const elementsWithFilter = document.querySelectorAll(`[style*="url(#${filterId})"]`);
398+
if (elementsWithFilter.length === 0) {
399+
svgElement.parentNode.removeChild(svgElement);
400+
this.svgFilters.delete(filterId);
401+
}
402+
}
403+
}
404+
405+
/**
406+
* Remove SVG filter from an element
407+
* @param {HTMLElement} element - Element to remove filter from
408+
*/
409+
removeSVGFilter(element) {
410+
const filterId = this.elementFilterMap.get(element);
411+
if (filterId) {
412+
// Remove filter style
413+
if (element.style.filter) {
414+
element.style.filter = element.style.filter.replace(`url(#${filterId})`, '').trim();
415+
if (!element.style.filter) {
416+
element.style.removeProperty('filter');
417+
}
418+
}
419+
420+
this.elementFilterMap.delete(element);
421+
this.cleanupSVGFilter(filterId);
422+
}
423+
}
424+
294425
/**
295426
* Generate inline styles for a glass configuration
296427
* @param {GlassConfig} [config={}] - Glass configuration options
@@ -307,6 +438,7 @@
307438
gradient = false,
308439
gradientFrom = 'rgba(255,255,255,0.1)',
309440
gradientTo = 'rgba(255,255,255,0.05)',
441+
svgFilterId
310442
} = config;
311443

312444
const shadowMap = {
@@ -316,7 +448,7 @@
316448
heavy: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
317449
};
318450

319-
return {
451+
const styles = {
320452
backdropFilter: `blur(${blur}px)`,
321453
WebkitBackdropFilter: `blur(${blur}px)`,
322454
background: gradient
@@ -328,6 +460,13 @@
328460
position: 'relative',
329461
overflow: 'hidden',
330462
};
463+
464+
// Add SVG filter if specified
465+
if (svgFilterId) {
466+
styles.filter = `url(#${svgFilterId})`;
467+
}
468+
469+
return styles;
331470
}
332471

333472
/**
@@ -505,6 +644,16 @@ ${cssProperties}
505644
<h3>Colored Glass</h3>
506645
<p>Beautiful gradients with color presets.</p>
507646
</div>
647+
648+
<div class="liqglass-base liqglass-refraction liqglass-card liqglass-animated liqglass-hover">
649+
<h3>Refraction Glass</h3>
650+
<p>Advanced glass with refraction effects.</p>
651+
</div>
652+
653+
<div class="liqglass-base liqglass-distortion liqglass-card liqglass-animated liqglass-hover">
654+
<h3>Distortion Glass</h3>
655+
<p>Complex distortion with lighting effects.</p>
656+
</div>
508657
</div>
509658
</div>
510659
@@ -513,22 +662,28 @@ ${cssProperties}
513662
const liqGlass = new LiqGlass();
514663
console.log('LiqGlass v' + liqGlass.getVersion() + ' initialized');
515664
516-
// Example: Create a dynamic glass element
517-
const dynamicGlass = liqGlass.createGlassElement({
518-
blur: 18,
519-
opacity: 0.2,
520-
borderRadius: 25,
521-
gradient: true,
522-
gradientFrom: 'rgba(147, 51, 234, 0.3)',
523-
gradientTo: 'rgba(79, 70, 229, 0.1)',
665+
// Example: Create dynamic glass elements with new presets
666+
const refractionGlass = liqGlass.createGlassElement({
667+
...liqGlass.getPreset('refraction'),
668+
className: 'liqglass-card',
524669
animated: true,
525-
hoverEffect: true,
526-
className: 'liqglass-card'
670+
hoverEffect: true
527671
});
672+
refractionGlass.innerHTML = '<h3>Dynamic Refraction</h3><p>Created with JavaScript!</p>';
673+
refractionGlass.style.marginTop = '2rem';
528674
529-
dynamicGlass.innerHTML = '<h3>Dynamic Glass</h3><p>Created with JavaScript!</p>';
530-
dynamicGlass.style.marginTop = '2rem';
531-
document.querySelector('.container').appendChild(dynamicGlass);
675+
const distortionGlass = liqGlass.createGlassElement({
676+
...liqGlass.getPreset('distortion'),
677+
className: 'liqglass-card',
678+
animated: true,
679+
hoverEffect: true
680+
});
681+
distortionGlass.innerHTML = '<h3>Dynamic Distortion</h3><p>Complex SVG filters in action!</p>';
682+
distortionGlass.style.marginTop = '1rem';
683+
684+
const container = document.querySelector('.container');
685+
container.appendChild(refractionGlass);
686+
container.appendChild(distortionGlass);
532687
</script>
533688
</body>
534689
</html>`;
@@ -564,9 +719,18 @@ ${cssProperties}
564719
document.head.removeChild(this.styleElement);
565720
this.styleElement = null;
566721
}
722+
723+
// Clean up all SVG filters
724+
for (const [filterId, svgElement] of this.svgFilters) {
725+
if (svgElement.parentNode) {
726+
svgElement.parentNode.removeChild(svgElement);
727+
}
728+
}
729+
567730
this.presets.clear();
568731
this.colorPresets.clear();
569732
this.generatedStyles.clear();
733+
this.svgFilters.clear();
570734
}
571735
}
572736

@@ -604,21 +768,25 @@ ${cssProperties}
604768
* borderRadius: 20
605769
* });
606770
*
607-
* // Using singleton
608-
* const glassSingleton = LiqGlass.getInstance();
609-
* glassSingleton.applyGlassStyles(document.getElementById('myDiv'), {
610-
* preset: 'frosted'
771+
* // Using new SVG filter presets
772+
* const refractionElement = glass.createGlassElement({
773+
* ...glass.getPreset('refraction'),
774+
* className: 'my-refraction-glass'
611775
* });
612776
*
613-
* // Generate CSS
614-
* const css = glass.generateVanillaCSS();
777+
* const distortionElement = glass.createGlassElement({
778+
* ...glass.getPreset('distortion'),
779+
* className: 'my-distortion-glass'
780+
* });
615781
*
616-
* // Create custom presets
617-
* glass.addPreset('custom', {
618-
* blur: 25,
619-
* opacity: 0.3,
620-
* gradient: true,
621-
* gradientFrom: 'rgba(255, 0, 0, 0.2)',
622-
* gradientTo: 'rgba(255, 100, 100, 0.1)'
782+
* // Custom SVG filter
783+
* const customElement = glass.createGlassElement({
784+
* blur: 10,
785+
* opacity: 0.15,
786+
* svgFilter: '<svg style="display: none"><filter id="custom-filter">...</filter></svg>',
787+
* svgFilterId: 'custom-filter'
623788
* });
789+
*
790+
* // Remove SVG filter when needed
791+
* glass.removeSVGFilter(customElement);
624792
*/

0 commit comments

Comments
 (0)