模式图在Safari中动态加载行为不端

时间:2018-05-04 10:43:54

标签: javascript jquery canvas

下面提供了一个用于在点击时更改图像的脚本,更改将在画布中受到影响。

该脚本在Firefox和Chrome中正常运行,但在Safari

中无效

可能是什么原因?

<script>
  $(function() {

    var house = document.getElementById("house");
    var ctxHouse = house.getContext("2d");
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var canvas2 = document.getElementById("canvas2");
    var ctxHand = canvas2.getContext("2d");
    var FabricLink;
    var imageObj = new Image();
    var red = new Image();
    red.onload = function() {
      canvas.width = red.width;
      canvas.height = red.height;

      var houseImage = new Image();
      houseImage.onload = function() {
        house.width = houseImage.width;
        house.height = houseImage.height;
        ctxHouse.drawImage(houseImage, 0, 0);
      }
      houseImage.src = "images/img.jpg";

      ctx.drawImage(red, 0, 0);


      imageObj.onload = function() {
        var pattern = ctx.createPattern(imageObj, 'repeat');
        ctx.globalCompositeOperation = 'source-in';
        ctx.rect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = pattern;
        ctx.fill();
      };
      $(imageObj).attr('src', 'images/' + FabricLink + '.png');
    }
    red.src = "images/img.png";
    var imageObj2 = new Image();
    var blue = new Image();
    blue.onload = function() {
      canvas2.width = blue.width;
      canvas2.height = blue.height;

      var houseImage = new Image();
      houseImage.onload = function() {
        house.width = houseImage.width;
        house.height = houseImage.height;
        ctxHouse.drawImage(houseImage, 0, 0);
      }
      houseImage.src = "images/img.jpg";

      ctxHand.drawImage(blue, 0, 0);


      imageObj2.onload = function() {
        var pattern = ctx.createPattern(imageObj2, 'repeat');
        ctxHand.globalCompositeOperation = 'source-in';
        ctxHand.rect(0, 0, canvas2.width, canvas2.height);
        ctxHand.fillStyle = pattern;
        ctxHand.fill();
      };
      $(imageObj2).attr('src', 'images/' + FabricLink + '.png');
    }
    blue.src = "images/img.png";




    $('#style li').click(
      function() {
        //we get our current filename and use it for the src
        var linkIndex = $(this).attr("data-filename");
        $(red).attr('src', 'images/' + linkIndex + '.png');
      }
    );

    $('#Sleeves li').click(
      function() {
        $("#canvas2").addClass("show-z");
        //we get our current filename and use it for the src
        var SleevesLink = $(this).attr("data-filename");
        $(blue).attr('src', 'images/' + SleevesLink + '.png');
      }
    );

    $('#Fabric li').click(
      function() {
        //we get our current filename and use it for the src
        FabricLink = $(this).attr("data-filename");
        $(imageObj2).attr('src', 'images/' + FabricLink + '.png');
        $(imageObj).attr('src', 'images/' + FabricLink + '.png');


      }
    );

    $("#Fabric li:first-child").click();




  }); // end $(function(){});
</script>

在调试时,我们可以看到 imageObj.onload 在第一次点击时没有被触发,只有在刷新时才会在Safari中发生变化。

jsfiddle.net/qvfx3kz7(在小提琴图片中没有加载,但是添加了完整的代码)

1 个答案:

答案 0 :(得分:1)

我不确定Safari究竟出现了什么问题,但我可以看到,只有在请求时才尝试加载资源,使得所有内容过于复杂,这会导致您设置的回调噩梦。 / p>

相反,请准备好您的资产,以便只加载一次。由于您使用的是模式,我将假设每个模式实际上都是一个小图像 因此,不是加载每个小图案图像,而是加载一个sprite-sheet,其中包含all your patterns 从那里,您将能够同步动态生成CanvasPattern,而无需关心任何加载回调。为此,您必须使用第二个屏幕外的画布,您将使用它作为createPattern()方法的来源:

&#13;
&#13;
// really dummy implementation...
function AssetsLoader() {}
AssetsLoader.prototype = Object.create({
  addImage: function(objs, cb) {
    if (!objs || typeof objs !== 'object') return;
    if (!Array.isArray(objs)) objs = [];
    var toLoad = objs.length,
      imgs = objs.map(loadImage, this);

    function loadImage(obj) {
      if (!obj.src) return;
      this.toLoad++;
      var img = new Image();
      img.src = obj.src;
      img.onload = onimgload;
      img.onerror = onimgerror;
      return obj.img = img;
    }

    function onimgload(evt) {
      if (--toLoad <= 0 && typeof cb === 'function') cb(imgs);
    }

    function onimgerror(evt) {
      console.warn('failed to load image at ', evt.target.src);
    }
  }
});
// Some info about our assets, there are an infinity of ways to deal with it,
// You would have to determine yourself what's best for your own case
var dests = {
  sofa: {
    name: 'sofa',
    src: 'https://i.stack.imgur.com/ryO42.png'
  },
  shirt: {
    name: 'shirt',
    src: 'https://i.stack.imgur.com/cPNbe.png'
  }
};
var patterns = {
  name: 'patterns',
  src: 'https://i.stack.imgur.com/TdIAJ.png',
  positions: {
    orange: {
      x: 0,
      y: 0,
      width: 173,
      height: 173,
      out_width: 75,
      out_height: 75
    },
    violet: {
      x: 173,
      y: 0,
      width: 173,
      height: 173,
      out_width: 35,
      out_height: 35
    },
    psyche: {
      x: 0,
      y: 173,
      width: 173,
      height: 173,
      out_width: 25,
      out_height: 25
    },
    pink: {
      x: 173,
      y: 173,
      width: 173,
      height: 173,
      out_width: 125,
      out_height: 125
    }
  }
}

var assets = new AssetsLoader();
// first load all our images, and only then, start the whole thing
assets.addImage([dests.shirt, dests.sofa, patterns], init);


function init() {
  // populate our selects
  for (var key in dests) {
    dest_select.appendChild(new Option(key, key));
  }
  for (var key in patterns.positions) {
    pat_select.appendChild(new Option(key, key));
  }
  dest_select.onchange = pat_select.onchange = draw;

  var ctx = canvas.getContext('2d');
  var offscreenCtx = document.createElement('canvas').getContext('2d');

  draw();

  function draw() {
    var dest = dests[dest_select.value].img;
    ctx.canvas.width = dest.width;
    ctx.canvas.height = dest.height;

    ctx.globalCompositeOperation = 'source-over';
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(dest, 0, 0, canvas.width, canvas.height);
    ctx.globalCompositeOperation = 'source-in';

    // here we generate the CanvasPattern
    ctx.fillStyle = getPattern(pat_select.value);
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    ctx.globalCompositeOperation = 'luminosity';
    ctx.drawImage(dest, 0, 0, canvas.width, canvas.height);
  }
  // now that we have our patterns loaded in a single sprite-sheet,
  // we can generate the CanvasPatterns synchronously
  function getPattern(key) {
    var pos = patterns.positions[key]; // get our pattern's position in our dictionary
    // resize the offscreen canvas so it matches our pattern
    offscreenCtx.canvas.width = pos.out_width;
    offscreenCtx.canvas.height = pos.out_height;
    offscreenCtx.drawImage(patterns.img, pos.x, pos.y, pos.width, pos.height, 0, 0, pos.out_width, pos.out_height);
    return offscreenCtx.createPattern(offscreenCtx.canvas, 'repeat');
  }
}
&#13;
<select id="dest_select"></select>
<select id="pat_select"></select>
<br><br><br>
<canvas id="canvas"></canvas>
&#13;
&#13;
&#13;