सीएसएस(jQuery एसवीजी छवि प्रतिस्थापन) का उपयोग कर एसवीजी छवि का रंग कैसे बदलें?




css svg (9)

@ ड्रू बेकर ने समस्या को हल करने के लिए एक अच्छा समाधान दिया। कोड ठीक से काम करता है। हालांकि, जो लोग AngularJs का उपयोग करते हैं उन्हें jQuery पर बहुत निर्भरता मिल सकती है। नतीजतन, मैंने सोचा कि AngularJS उपयोगकर्ताओं के लिए पेस्ट करना एक अच्छा विचार है, @Drew बेकर के समाधान के बाद एक कोड।

एक ही कोड के AngularJs रास्ता

1. एचटीएमएल : एचटीएमएल फाइल में बोले टैग का प्रयोग करें:

<svg-image src="/icons/my.svg" class="any-class-you-wish"></svg-image>

2. निर्देश : यह निर्देश होगा कि आपको टैग को पहचानने की आवश्यकता होगी:

'use strict';
angular.module('myApp')
  .directive('svgImage', ['$http', function($http) {
    return {
      restrict: 'E',
      link: function(scope, element) {
        var imgURL = element.attr('src');
        // if you want to use ng-include, then
        // instead of the above line write the bellow:
        // var imgURL = element.attr('ng-include');
        var request = $http.get(
          imgURL,
          {'Content-Type': 'application/xml'}
        );

        scope.manipulateImgNode = function(data, elem){
          var $svg = angular.element(data)[4];
          var imgClass = elem.attr('class');
          if(typeof(imgClass) !== 'undefined') {
            var classes = imgClass.split(' ');
            for(var i = 0; i < classes.length; ++i){
              $svg.classList.add(classes[i]);
            }
          }
          $svg.removeAttribute('xmlns:a');
          return $svg;
        };

        request.success(function(data){
          element.replaceWith(scope.manipulateImgNode(data, element));
        });
      }
    };
  }]);

3. सीएसएस :

.any-class-you-wish{
    border: 1px solid red;
    height: 300px;
    width:  120px
}

4. कर्म-चमेली के साथ यूनिट-टेस्ट :

'use strict';

describe('Directive: svgImage', function() {

  var $rootScope, $compile, element, scope, $httpBackend, apiUrl, data;

  beforeEach(function() {
    module('myApp');

    inject(function($injector) {
      $rootScope = $injector.get('$rootScope');
      $compile = $injector.get('$compile');
      $httpBackend = $injector.get('$httpBackend');
      apiUrl = $injector.get('apiUrl');
    });

    scope = $rootScope.$new();
    element = angular.element('<svg-image src="/icons/icon-man.svg" class="svg"></svg-image>');
    element = $compile(element)(scope);

    spyOn(scope, 'manipulateImgNode').andCallThrough();
    $httpBackend.whenGET(apiUrl + 'me').respond(200, {});

    data = '<?xml version="1.0" encoding="utf-8"?>' +
      '<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->' +
      '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' +
      '<!-- Obj -->' +
      '<!-- Obj -->' +
      '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"' +
      'width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">' +
        '<g>' +
          '<path fill="#F4A902" d=""/>' +
          '<path fill="#F4A902" d=""/>' +
        '</g>' +
      '</svg>';
    $httpBackend.expectGET('/icons/icon-man.svg').respond(200, data);
  });

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  it('should call manipulateImgNode atleast once', function () {
    $httpBackend.flush();
    expect(scope.manipulateImgNode.callCount).toBe(1);
  });

  it('should return correct result', function () {
    $httpBackend.flush();
    var result = scope.manipulateImgNode(data, element);
    expect(result).toBeDefined();
  });

  it('should define classes', function () {
    $httpBackend.flush();
    var result = scope.manipulateImgNode(data, element);
    var classList = ["svg"];
    expect(result.classList[0]).toBe(classList[0]);
  });
});

यह कोड के एक आसान टुकड़े का एक स्वयं प्रश्नोत्तर है जिसके साथ मैं आया था।

वर्तमान में, एसवीजी छवि को एम्बेड करने का कोई आसान तरीका नहीं है और उसके बाद सीएसएस के माध्यम से एसवीजी तत्वों तक पहुंच है। जेएस एसवीजी ढांचे का उपयोग करने के कई तरीके हैं, लेकिन यदि आप जो भी कर रहे हैं, वे रोलओवर राज्य के साथ एक साधारण आइकन बना रहे हैं तो वे अत्यधिक जटिल हैं।

तो यहां मैं जो आया हूं, जो मुझे लगता है कि वेबसाइट पर एसवीजी फाइलों का उपयोग करने का सबसे आसान तरीका है। यह अपनी अवधारणा को प्रारंभिक टेक्स्ट-टू-इमेज प्रतिस्थापन विधियों से लेता है, लेकिन जहां तक ​​मुझे पता है कि एसवीजी के लिए कभी नहीं किया गया है।

ये है प्रश्न:

मैं एक एसवीजी कैसे एम्बेड करूं और जेएस-एसवीजी ढांचे का उपयोग किये बिना सीएसएस में अपना रंग बदलूं?


अंदाज

svg path {
    fill: #000;
}

लिपि

$(document).ready(function() {
    $('img[src$=".svg"]').each(function() {
        var $img = jQuery(this);
        var imgURL = $img.attr('src');
        var attributes = $img.prop("attributes");

        $.get(imgURL, function(data) {
            // Get the SVG tag, ignore the rest
            var $svg = jQuery(data).find('svg');

            // Remove any invalid XML tags
            $svg = $svg.removeAttr('xmlns:a');

            // Loop through IMG attributes and apply on SVG
            $.each(attributes, function() {
                $svg.attr(this.name, this.value);
            });

            // Replace IMG with SVG
            $img.replaceWith($svg);
        }, 'xml');
    });
});

अब आप सबसे आधुनिक ब्राउज़रों में सीएसएस filter प्रॉपर्टी का उपयोग कर सकते हैं (एज सहित, लेकिन आईई 11 नहीं)। यह एसवीजी छवियों के साथ-साथ अन्य तत्वों पर भी काम करता है। आप रंगों को संशोधित करने के लिए ह्यू-रोटेट या उलटा उपयोग कर सकते हैं, हालांकि वे आपको अलग-अलग रंगों को स्वतंत्र रूप से संशोधित नहीं करने देते हैं। मैं एक आइकन के "अक्षम" संस्करण को दिखाने के लिए निम्न सीएसएस वर्ग का उपयोग करता हूं (जहां मूल संतृप्त रंग के साथ एक एसवीजी तस्वीर है):

.disabled {
    opacity: 0.4;
    filter: grayscale(100%);
    -webkit-filter: grayscale(100%);
}

इससे अधिकांश ब्राउज़रों में हल्का भूरा हो जाता है। आईई (और शायद ओपेरा मिनी, जिसे मैंने परीक्षण नहीं किया है) में यह अस्पष्टता संपत्ति द्वारा फीका हुआ है, जो अभी भी बहुत अच्छा दिखता है, हालांकि यह भूरा नहीं है।

Twemoji घंटी आइकन के लिए चार अलग-अलग सीएसएस वर्गों के साथ एक उदाहरण यहां दिया गया है: मूल (पीला), उपरोक्त "अक्षम" वर्ग, hue-rotate (हरा), और invert (नीला)।

.twa-bell {
  background-image: url("https://twemoji.maxcdn.com/svg/1f514.svg");
  display: inline-block;
  background-repeat: no-repeat;
  background-position: center center;
  height: 3em;
  width: 3em;
  margin: 0 0.15em 0 0.3em;
  vertical-align: -0.3em;
  background-size: 3em 3em;
}
.grey-out {
  opacity: 0.4;
  filter: grayscale(100%);
  -webkit-filter: grayscale(100%);
}
.hue-rotate {
  filter: hue-rotate(90deg);
  -webkit-filter: hue-rotate(90deg);
}
.invert {
  filter: invert(100%);
  -webkit-filter: invert(100%);
}
<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <span class="twa-bell"></span>
  <span class="twa-bell grey-out"></span>
  <span class="twa-bell hue-rotate"></span>
  <span class="twa-bell invert"></span>
</body>

</html>


चयनित समाधान ठीक है यदि आप चाहते हैं कि jQuery आपके डीओएम में सभी svg तत्वों को संसाधित करे और आपका डीओएम उचित आकार का हो। लेकिन यदि आपका डोम बड़ा है और आप अपने डोम के हिस्सों को गतिशील रूप से लोड करने का निर्णय लेते हैं, तो वास्तव में यह पूरी तरह से एसवीजी तत्वों को अद्यतन करने के लिए पूरे डोम को पुन: स्कैन करने का कोई मतलब नहीं है। इसके बजाय, ऐसा करने के लिए एक jQuery प्लगइन का उपयोग करें:

/**
 * A jQuery plugin that loads an svg file and replaces the jQuery object with its contents.
 *
 * The path to the svg file is specified in the src attribute (which normally does not exist for an svg element).
 *
 * The width, height and class attributes in the loaded svg will be replaced by those that exist in the jQuery object's
 * underlying html. Note: All other attributes in the original element are lost including the style attribute. Place
 * any styles in a style class instead.
 */
(function ($) {
    $.fn.svgLoader = function () {
        var src = $(this).attr("src");
        var width = this.attr("width");
        var height = this.attr("height");
        var cls = this.attr("class");
        var ctx = $(this);

        // Get the svg file and replace the <svg> element.
        $.ajax({
            url: src,
            cache: false
        }).done(function (html) {
            let svg = $(html);
            svg.attr("width", width);
            svg.attr("height", height);
            svg.attr("class", cls);
            var newHtml = $('<a></a>').append(svg.clone()).html();
            ctx.replaceWith(newHtml);
        });

        return this;
    };

}(jQuery));

अपने एचटीएमएल में, निम्नानुसार एक svg तत्व निर्दिष्ट करें:

<svg src="images/someSvgFile.svg" height="45" width="45" class="mySVGClass"/>

और प्लगइन लागू करें:

$(".mySVGClass").svgLoader();

मैंने AngularJS के साथ इस मुद्दे को हल करने के लिए एक निर्देश लिखा था। यह यहां उपलब्ध है - ngReusableSvg

यह एसवीजी तत्व को प्रतिपादित करने के बाद प्रतिस्थापित करता है, और इसे एक div तत्व के अंदर रखता है, जिससे इसका सीएसएस आसानी से बदल सकता है। यह अलग-अलग आकारों / रंगों का उपयोग करके अलग-अलग स्थानों में एक ही एसवीजी फ़ाइल का उपयोग करने में मदद करता है।

उपयोग सरल है:

<object oa-reusable-svg
        data="my_icon.svg"
        type="image/svg+xml"
        class="svg-class"
        height="30"  // given to prevent UI glitches at switch time
        width="30">
</object>

उसके बाद, आप आसानी से प्राप्त कर सकते हैं:

.svg-class svg {
    fill: red; // whichever color you want
}

यदि आप अपने पृष्ठ में फ़ाइलों को शामिल कर सकते हैं (PHP शामिल या अपने सीएमएस के माध्यम से शामिल करें), तो आप एसवीजी कोड जोड़ सकते हैं और इसे अपने पेज में शामिल कर सकते हैं। यह पेज में एसवीजी स्रोत चिपकाने जैसा ही काम करता है, लेकिन पेज मार्कअप क्लीनर बनाता है।

लाभ यह है कि आप अपने एसवीजी के हिस्सों को होवर के लिए सीएसएस के माध्यम से लक्षित कर सकते हैं - कोई जावास्क्रिप्ट आवश्यक नहीं है।

http://codepen.io/chriscoyier/pen/evcBu

आपको बस इस तरह एक सीएसएस नियम का उपयोग करना होगा:

#pathidorclass:hover { fill: #303 !important; }

ध्यान दें कि भरने के रंग को ओवरराइड करने के लिए !important बिट आवश्यक है।


यहां कोई फ्रेमवर्क कोड नहीं है, केवल शुद्ध जेएस:

document.querySelectorAll('img.svg').forEach(function(element) {
            var imgID = element.getAttribute('id')
            var imgClass = element.getAttribute('class')
            var imgURL = element.getAttribute('src')

            xhr = new XMLHttpRequest()
            xhr.onreadystatechange = function() {
                if(xhr.readyState == 4 && xhr.status == 200) {
                    var svg = xhr.responseXML.getElementsByTagName('svg')[0];

                    if(imgID != null) {
                         svg.setAttribute('id', imgID);
                    }

                    if(imgClass != null) {
                         svg.setAttribute('class', imgClass + ' replaced-svg');
                    }

                    svg.removeAttribute('xmlns:a')

                    if(!svg.hasAttribute('viewBox') && svg.hasAttribute('height') && svg.hasAttribute('width')) {
                        svg.setAttribute('viewBox', '0 0 ' + svg.getAttribute('height') + ' ' + svg.getAttribute('width'))
                    }
                    element.parentElement.replaceChild(svg, element)
                }
            }
            xhr.open('GET', imgURL, true)
            xhr.send(null)
        })

वैकल्पिक रूप से आप सीएसएस mask उपयोग कर सकते हैं, दिया गया ब्राउज़र समर्थन अच्छा नहीं है लेकिन आप फॉलबैक का उपयोग कर सकते हैं

.frame {
    background: blue;
    -webkit-mask: url(image.svg) center / contain no-repeat;
}

स्वीकार किए गए उत्तर के आधार पर knockout.js लिए एक संस्करण यहां दिया गया है:

महत्वपूर्ण: इसे वास्तव में बदलने के लिए भी jQuery की आवश्यकता होती है, लेकिन मैंने सोचा कि यह कुछ के लिए उपयोगी हो सकता है।

ko.bindingHandlers.svgConvert =
    {
        'init': function ()
        {
            return { 'controlsDescendantBindings': true };
        },

        'update': function (element, valueAccessor, allBindings, viewModel, bindingContext)
        {
            var $img = $(element);
            var imgID = $img.attr('id');
            var imgClass = $img.attr('class');
            var imgURL = $img.attr('src');

            $.get(imgURL, function (data)
            {
                // Get the SVG tag, ignore the rest
                var $svg = $(data).find('svg');

                // Add replaced image's ID to the new SVG
                if (typeof imgID !== 'undefined')
                {
                    $svg = $svg.attr('id', imgID);
                }
                // Add replaced image's classes to the new SVG
                if (typeof imgClass !== 'undefined')
                {
                    $svg = $svg.attr('class', imgClass + ' replaced-svg');
                }

                // Remove any invalid XML tags as per http://validator.w3.org
                $svg = $svg.removeAttr('xmlns:a');

                // Replace image with new SVG
                $img.replaceWith($svg);

            }, 'xml');

        }
    };

फिर बस अपने data-bind="svgConvert: true" टैग पर data-bind="svgConvert: true" लागू करें।

यह समाधान पूरी तरह से एसवीजी के साथ img टैग को प्रतिस्थापित करता है और किसी भी अतिरिक्त बाइंडिंग का सम्मान नहीं किया जाएगा।





svg