ecomfe / zrender

A lightweight graphic library providing 2d draw for Apache ECharts
https://ecomfe.github.io/zrender-doc/public/
BSD 3-Clause "New" or "Revised" License
6.02k stars 1.56k forks source link

图片shape 在ie8下,应用position,scale 属性后, 图片会出现位置为(0,0)的情况 #49

Open ledkk opened 10 years ago

ledkk commented 10 years ago

在ie8下, 针对图片,在使用了position 和scale后, 会出现图片位置不对的问题, 但图片上的文字的位置是正确的情况,具体情况如图: qq20131130173038 qq20131130173046

ledkk commented 10 years ago

琢磨了半天, 感觉可能是excanvas的问题, 在drawImage 的时候,可能会有些问题。。。。。 还好在网上找到了一个解决方式, 是用div缩放的方式解决的。。。 相关网址为: http://dev.sencha.com/playpen/tm/excanvas-patch/testcases.html merge后的代码如下:

// Copyright 2006 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License.

// Known Issues: // // * Patterns only support repeat. // * Radial gradient are not implemented. The VML version of these look very // different from the canvas one. // * Clipping paths are not implemented. // * Coordsize. The width and height attribute have higher priority than the // width and height style values which isn't correct. // * Painting mode isn't implemented. // * Canvas width/height should is using content-box by default. IE in // Quirks mode will draw the canvas using border-box. Either change your // doctype to HTML5 // (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) // or use Box Sizing Behavior from WebFX // (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) // * Non uniform scaling does not correctly scale strokes. // * Optimize. There is always room for speed improvements.

// AMD by kener.linfeng@gmail.com define(function(require) {

// Only add this code if we do not already have a canvas implementation if (!document.createElement('canvas').getContext) {

(function() {

// alias some functions to make (compiled) code shorter var m = Math; var mr = m.round; var ms = m.sin; var mc = m.cos; var abs = m.abs; var sqrt = m.sqrt;

// this is used for sub pixel precision var Z = 10; var Z2 = Z / 2;

var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];

/**

');

this.element_.insertAdjacentHTML('beforeEnd', vmlStr.join('')); };

contextPrototype.stroke = function(aFill) { var lineStr = []; var lineOpen = false;

var W = 10; var H = 10;

lineStr.push('<gvml:shape', ' filled="', !!aFill, '"', ' style="position:absolute;width:', W, 'px;height:', H, 'px;"', ' coordorigin="0,0"', ' coordsize="', Z * W, ',', Z * H, '"', ' stroked="', !aFill, '"', ' path="');

var newSeq = false; var min = {x: null, y: null}; var max = {x: null, y: null};

for (var i = 0; i < this.currentPath.length; i++) { var p = this.currentPath[i]; var c;

switch (p.type) {
case 'moveTo':
  c = p;
  lineStr.push(' m ', mr(p.x), ',', mr(p.y));
  break;
case 'lineTo':
  lineStr.push(' l ', mr(p.x), ',', mr(p.y));
  break;
case 'close':
  lineStr.push(' x ');
  p = null;
  break;
case 'bezierCurveTo':
  lineStr.push(' c ',
               mr(p.cp1x), ',', mr(p.cp1y), ',',
               mr(p.cp2x), ',', mr(p.cp2y), ',',
               mr(p.x), ',', mr(p.y));
  break;
case 'at':
case 'wa':
  lineStr.push(' ', p.type, ' ',
               mr(p.x - this.arcScaleX_ * p.radius), ',',
               mr(p.y - this.arcScaleY_ * p.radius), ' ',
               mr(p.x + this.arcScaleX_ * p.radius), ',',
               mr(p.y + this.arcScaleY_ * p.radius), ' ',
               mr(p.xStart), ',', mr(p.yStart), ' ',
               mr(p.xEnd), ',', mr(p.yEnd));
  break;
}

// TODO: Following is broken for curves due to
//       move to proper paths.

// Figure out dimensions so we can do gradient fills
// properly
if (p) {
if (min.x == null || p.x < min.x) {
  min.x = p.x;
}
if (max.x == null || p.x > max.x) {
  max.x = p.x;
}
if (min.y == null || p.y < min.y) {
  min.y = p.y;
}
if (max.y == null || p.y > max.y) {
  max.y = p.y;
}
}

} lineStr.push(' ">');

if (!aFill) { appendStroke(this, lineStr); } else { appendFill(this, lineStr, min, max); }

lineStr.push('</gvml:shape>');

this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); };

function appendStroke(ctx, lineStr) { var a = processStyle(ctx.strokeStyle); var color = a.color; var opacity = a.alpha * ctx.globalAlpha; var lineWidth = ctx.lineScale_ * ctx.lineWidth;

// VML cannot correctly render a line if the width is less than 1px. // In that case, we dilute the color to make the line look thinner. if (lineWidth < 1) { opacity *= lineWidth; }

lineStr.push( '<gvml:stroke', ' opacity="', opacity, '"', ' joinstyle="', ctx.lineJoin, '"', ' miterlimit="', ctx.miterLimit, '"', ' endcap="', processLineCap(ctx.lineCap), '"', ' weight="', lineWidth, 'px"', ' color="', color, '" />' ); }

function appendFill(ctx, lineStr, min, max) { var fillStyle = ctx.fillStyle; var arcScaleX = ctx.arcScaleX; var arcScaleY = ctx.arcScaleY; var width = max.x - min.x; var height = max.y - min.y; if (fillStyle instanceof CanvasGradient_) { // TODO: Gradients transformed with the transformation matrix. var angle = 0; var focus = {x: 0, y: 0};

// additional offset
var shift = 0;
// scale factor for offset
var expansion = 1;

if (fillStyle.type_ == 'gradient') {
var x0 = fillStyle.x0_ / arcScaleX;
var y0 = fillStyle.y0_ / arcScaleY;
var x1 = fillStyle.x1_ / arcScaleX;
var y1 = fillStyle.y1_ / arcScaleY;
var p0 = getCoords(ctx, x0, y0);
var p1 = getCoords(ctx, x1, y1);
var dx = p1.x - p0.x;
var dy = p1.y - p0.y;
angle = Math.atan2(dx, dy) * 180 / Math.PI;

// The angle should be a non-negative number.
if (angle < 0) {
  angle += 360;
}

// Very small angles produce an unexpected result because they are
// converted to a scientific notation string.
if (angle < 1e-6) {
  angle = 0;
}
} else {
var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
focus = {
  x: (p0.x - min.x) / width,
  y: (p0.y - min.y) / height
};

width  /= arcScaleX * Z;
height /= arcScaleY * Z;
var dimension = m.max(width, height);
shift = 2 * fillStyle.r0_ / dimension;
expansion = 2 * fillStyle.r1_ / dimension - shift;
}

// We need to sort the color stops in ascending order by offset,
// otherwise IE won't interpret it correctly.
var stops = fillStyle.colors_;
stops.sort(function(cs1, cs2) {
return cs1.offset - cs2.offset;
});

var length = stops.length;
var color1 = stops[0].color;
var color2 = stops[length - 1].color;
var opacity1 = stops[0].alpha * ctx.globalAlpha;
var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;

var colors = [];
for (var i = 0; i < length; i++) {
var stop = stops[i];
colors.push(stop.offset * expansion + shift + ' ' + stop.color);
}

// When colors attribute is used, the meanings of opacity and o:opacity2
// are reversed.
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
           ' method="none" focus="100%"',
           ' color="', color1, '"',
           ' color2="', color2, '"',
           ' colors="', colors.join(','), '"',
           ' opacity="', opacity2, '"',
           ' g_o_:opacity2="', opacity1, '"',
           ' angle="', angle, '"',
           ' focusposition="', focus.x, ',', focus.y, '" />');

} else if (fillStyle instanceof CanvasPattern_) { if (width && height) { var deltaLeft = -min.x; var deltaTop = -min.y; lineStr.push('<gvml:fill', ' position="', deltaLeft / width arcScaleX arcScaleX, ',', deltaTop / height arcScaleY arcScaleY, '"', ' type="tile"', // TODO: Figure out the correct size to fit the scale. //' size="', w, 'px ', h, 'px"', ' src="', fillStyle.src_, '" />'); } } else { var a = processStyle(ctx.fillStyle); var color = a.color; var opacity = a.alpha * ctx.globalAlpha; lineStr.push(''); } }

contextPrototype.fill = function() { this.stroke(true); };

contextPrototype.closePath = function() { this.currentPath_.push({type: 'close'}); };

function getCoords(ctx, aX, aY) { var m = ctx.m_; return { x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2, y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2 }; };

contextPrototype.save = function() { var o = {}; copyState(this, o); this.aStack.push(o); this.mStack.push(this.m); this.m = matrixMultiply(createMatrixIdentity(), this.m_); };

contextPrototype.restore = function() { if (this.aStack.length) { copyState(this.aStack.pop(), this); this.m = this.mStack.pop(); } };

function matrixIsFinite(m) { return isFinite(m[0][0]) && isFinite(m[0][1]) && isFinite(m[1][0]) && isFinite(m[1][1]) && isFinite(m[2][0]) && isFinite(m[2][1]); }

function setM(ctx, m, updateLineScale) { if (!matrixIsFinite(m)) { return; } ctx.m_ = m;

if (updateLineScale) { // Get the line scale. // Determinant of this.m means how much the area is enlarged by the // transformation. So its square root can be used as a scale factor // for width. var det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; ctx.lineScale = sqrt(abs(det)); } }

contextPrototype.translate = function(aX, aY) { var m1 = [ [1, 0, 0], [0, 1, 0], [aX, aY, 1] ];

setM(this, matrixMultiply(m1, this.m_), false); };

contextPrototype.rotate = function(aRot) { var c = mc(aRot); var s = ms(aRot);

var m1 = [ [c, s, 0], [-s, c, 0], [0, 0, 1] ];

setM(this, matrixMultiply(m1, this.m_), false); };

contextPrototype.scale = function(aX, aY) { this.arcScaleX *= aX; this.arcScaleY *= aY; var m1 = [ [aX, 0, 0], [0, aY, 0], [0, 0, 1] ];

setM(this, matrixMultiply(m1, this.m_), true); };

contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) { var m1 = [ [m11, m12, 0], [m21, m22, 0], [dx, dy, 1] ];

setM(this, matrixMultiply(m1, this.m_), true); };

contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) { var m = [ [m11, m12, 0], [m21, m22, 0], [dx, dy, 1] ];

setM(this, m, true); };

/**

  • The text drawing function.
  • The maxWidth argument isn't taken in account, since no browser supports
  • it yet. */ contextPrototype.drawText = function(text, x, y, maxWidth, stroke) { var m = this.m, delta = 1000, left = 0, right = delta, offset = {x: 0, y: 0}, lineStr = [];

    var fontStyle = getComputedStyle(processFontStyle(this.font), this.element_);

    var fontStyleString = buildStyle(fontStyle);

    var elementStyle = this.element_.currentStyle; var textAlign = this.textAlign.toLowerCase(); switch (textAlign) { case 'left': case 'center': case 'right': break; case 'end': textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left'; break; case 'start': textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left'; break; default: textAlign = 'left'; }

    // 1.75 is an arbitrary number, as there is no info about the text baseline switch (this.textBaseline) { case 'hanging': case 'top': offset.y = fontStyle.size / 1.75; break; case 'middle': break; default: case null: case 'alphabetic': case 'ideographic': case 'bottom': offset.y = -fontStyle.size / 2.25; break; }

    switch(textAlign) { case 'right': left = delta; right = 0.05; break; case 'center': left = right = delta / 2; break; }

    var d = getCoords(this, x + offset.x, y + offset.y);

    lineStr.push('<gvml:line from="', -left ,' 0" to="', right ,' 0.05" ', ' coordsize="100 100" coordorigin="0 0"', ' filled="', !stroke, '" stroked="', !!stroke, '" style="position:absolute;width:1px;height:1px;">');

    if (stroke) { appendStroke(this, lineStr); } else { // TODO: Fix the min and max params. appendFill(this, lineStr, {x: -left, y: 0}, {x: right, y: fontStyle.size}); }

    var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' + m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';

    var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);

    lineStr.push('<gvml:skew on="t" matrix="', skewM ,'" ', ' offset="', skewOffset, '" origin="', left ,' 0" />', '', '</gvml:line>');

    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); };

    contextPrototype.fillText = function(text, x, y, maxWidth) { this.drawText_(text, x, y, maxWidth, false); };

    contextPrototype.strokeText = function(text, x, y, maxWidth) { this.drawText_(text, x, y, maxWidth, true); };

    contextPrototype.measureText = function(text) { if (!this.textMeasureEl) { var s = ''; this.element.insertAdjacentHTML('beforeEnd', s); this.textMeasureEl = this.element.lastChild; } var doc = this.element.ownerDocument; this.textMeasureEl.innerHTML = ''; this.textMeasureEl.style.font = this.font; // Don't use innerHTML or innerText because they allow markup/whitespace. this.textMeasureEl.appendChild(doc.createTextNode(text)); return {width: this.textMeasureEl_.offsetWidth}; };

    /\ STUBS **/ contextPrototype.clip = function() { // TODO: Implement };

    contextPrototype.arcTo = function() { // TODO: Implement };

    contextPrototype.createPattern = function(image, repetition) { return new CanvasPattern_(image, repetition); };

    // Gradient / Pattern Stubs function CanvasGradient(aType) { this.type = aType; this.x0 = 0; this.y0 = 0; this.r0 = 0; this.x1 = 0; this.y1 = 0; this.r1 = 0; this.colors_ = []; }

    CanvasGradient.prototype.addColorStop = function(aOffset, aColor) { aColor = processStyle(aColor); this.colors.push({offset: aOffset, color: aColor.color, alpha: aColor.alpha}); };

    function CanvasPattern(image, repetition) { assertImageIsValid(image); switch (repetition) { case 'repeat': case null: case '': this.repetition = 'repeat'; break case 'repeat-x': case 'repeat-y': case 'no-repeat': this.repetition_ = repetition; break; default: throwException('SYNTAX_ERR'); }

    this.src = image.src; this.width = image.width; this.height_ = image.height; }

    function throwException(s) { throw new DOMException_(s); }

    function assertImageIsValid(img) { if (!img || img.nodeType != 1 || img.tagName != 'IMG') { throwException('TYPE_MISMATCH_ERR'); } if (img.readyState != 'complete') { throwException('INVALID_STATE_ERR'); } }

    function DOMException(s) { this.code = this[s]; this.message = s +': DOM Exception ' + this.code; } var p = DOMException.prototype = new Error; p.INDEX_SIZE_ERR = 1; p.DOMSTRING_SIZE_ERR = 2; p.HIERARCHY_REQUEST_ERR = 3; p.WRONG_DOCUMENT_ERR = 4; p.INVALID_CHARACTER_ERR = 5; p.NO_DATA_ALLOWED_ERR = 6; p.NO_MODIFICATION_ALLOWED_ERR = 7; p.NOT_FOUND_ERR = 8; p.NOT_SUPPORTED_ERR = 9; p.INUSE_ATTRIBUTE_ERR = 10; p.INVALID_STATE_ERR = 11; p.SYNTAX_ERR = 12; p.INVALID_MODIFICATION_ERR = 13; p.NAMESPACE_ERR = 14; p.INVALID_ACCESS_ERR = 15; p.VALIDATION_ERR = 16; p.TYPE_MISMATCH_ERR = 17;

    // set up externs G_vmlCanvasManager = GvmlCanvasManager; CanvasRenderingContext2D = CanvasRenderingContext2D; CanvasGradient = CanvasGradient; CanvasPattern = CanvasPattern; DOMException = DOMException; })();

  • } // if else { // make the canvas test simple by kener.linfeng@gmail.com G_vmlCanvasManager = false; } return G_vmlCanvasManager; }); // define

    显示的效果如下:

    qq20131130213446

    ledkk commented 10 years ago

    对这个项目的支持,难道只是作为工作来做,不是因为兴趣或者是其他之类的么? 为嘛周末都没人上来看问题的? 百度hi里好像也没人关注。。。。。

    kener commented 10 years ago

    出差中,谢谢建议,后续看看