画布用数字填充圆圈

时间:2016-09-15 13:59:04

标签: javascript canvas

我使用javascript(不是jQuery)。

简而言之

  • 填充圈
  • 圈子后透明
  • 以中间为中心的数字

这些值需要易于更改:

  • 半径
  • 背景颜色
  • 字体大小
  • 字体系列

如果数字会破坏圆圈,会关注。

原因

我需要这个的原因是我有一张谷歌地图。它有很多不同数字和颜色的标记。我找到了一个可以运行的脚本(在Chrome中)但需要D3才能工作。

这似乎是一项简单的任务。这就是为什么我希望我能在这种情况下留下D3

enter image description here

更新

这是我目前的代码。我已经阅读了更多内容,也许可以用SVG来做。什么工作。

var karta = (function () {
    var fn = {};
    var map;
    var latitude;
    var longitude;
    var zoom;
    var cache = {};
    var colors = [];
    var height = 75;
    var width = 75;

    // Init
    fn.init = function(options) {
        console.log(options);

        markers = options.markers;
        latitude = options.latitude;
        longitude = options.longitude;
        zoom = options.zoom;
        colors = fn.setColors();

        fn.setMap();
        fn.setMarkers();

        console.log(options);
    };

    // Set map
    fn.setMap = function() {
        map = new google.maps.Map(document.getElementById('map_canvas'), {
            zoom: zoom,
            center: {
                lat: latitude,
                lng: longitude
            },
            mapTypeId: 'satellite',
            mapTypeControl: false,
            zoomControl: false,
            streetViewControl: false,
        });
    };

    // Set markers
    fn.setMarkers = function() {
        var mytest = '<svg height="32" width="32"><foreignObject width="32" height="32" x="16" y="16" transform="translate(-16,-16)"><div class="circle" style="background: blue; border-radius: 100%; text-align: center; line-height: 32px; font-size: 12px;"><span style="display: inline-block; vertical-align: middle; color: #fff; font-weight: bold;">180</span></div></foreignObject></svg>';

        var myurl = 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(mytest);

        console.log(myurl);

        markers.forEach( function( point ) {
            fn.icon( point[0], function(src) {
                new google.maps.Marker({
                    position: new google.maps.LatLng( point[1], point[2] ),
                    map: map,
                    icon: {
                        url: myurl,
                        anchor: new google.maps.Point(25, 25),
                        origin: new google.maps.Point(0, 0),
                        scaledSize: new google.maps.Size(50, 50)
                    }
                });
            });
        });
    };

    // Set colors
    fn.setColors = function() {
        colors[65] = "E50000";
        colors[80] = "E52500";
        colors[95] = "E54A00";
        colors[110] = "E56F00";
        colors[125] = "E59400";
        colors[140] = "B79B00";
        colors[155] = "89A200";
        colors[170] = "5CA900";
        colors[185] = "2EB000";
        colors[250] = "00B700";
        return colors;
    };

    // Set circle
    fn.setCircle = function(svg, number) {
        var circles = svg.append('circle')
            .attr('cx', '27.2')
            .attr('cy', '27.2')
            .attr('r', '12')
            .style('fill', colors[number]);
        return circles;
    };

    // Set label
    fn.setLabel = function(svg, number) {
        var label = svg.append('text')
            .attr('dx', 27)
            .attr('dy', 32)
            .attr('text-anchor', 'middle')
            .attr('style', 'font-size: 12px; fill: #FFFFFF; font-family: Arial, Verdana; font-weight: bold')
            .text(number);
        return label;
    };

    // Set svg
    fn.setSvg = function(number) {
        var svg = d3.select(document.createElement('div')).append('svg')
            .attr('viewBox', '0 0 54.4 54.4')
            .append('g')

        fn.setCircle(svg, number);
        fn.setLabel(svg, number);
        return svg;
    };

    // Set image
    fn.setImage = function(number, node, callback) {
        var image = new Image();
        image.onload = (function(width, height) {
            var canvas = document.createElement('canvas');
            var context = canvas.getContext('2d');
            var dataURL;

            d3.select(canvas)
                .attr('width', width)
                .attr('height', height);

            context.drawImage(image, 0, 0, width, height);

            dataURL = canvas.toDataURL();
            generateIconCache[number] = dataURL;

            callback(dataURL);
        }).bind(this, width, height);

        var xmlSource = (new XMLSerializer()).serializeToString(node);
        image.src = 'data:image/svg+xml;base64,' + btoa(encodeURIComponent(xmlSource).replace(/%([0-9A-F]{2})/g, function(match, p1) {
            return String.fromCharCode('0x' + p1);
        }));
    };

    // Icon
    fn.icon = function( number, callback ) {
        if( cache[number] !== undefined ) {
            callback( cache[number] );
        }

        var svg = fn.setSvg(number);
        var node = svg.node().parentNode.cloneNode(true);

        d3.select(node).select('clippath').remove();

        fn.setImage(number, node, callback);
    }

    return fn;
})();

1 个答案:

答案 0 :(得分:2)

缩放文字以适合圆圈。

要缩放文本以适合圆形,您需要找到文本中对角线的角度。为此,您需要字体高度和字体宽度。字体高度位于2D上下文的font属性中。例如,“18px Arial”和字体宽度可以使用2D上下文textWidth = ctx.measureText(text).width来计算。

一旦获得字体宽度和字体高度,就可以得到textDiag = Math.atan(fontheight / fontWidth)的对角线角度。这将是圆圈上文本角落接触侧面的角度。

我们可以从圆周上的那一点到通过圆圈中间的水平线绘制一条线,为我们提供文本右边缘的位置。您可以使用halfWidth = Math.cos(textDiag) * radius获得该文本的总宽度应为该文本的两倍。

由于找到一个匹配给定文本宽度的点大小真的很痛苦,因此使用上下文转换矩阵缩放文本会更容易。

缩放只是所需的文本宽度除以已知的文本宽度。 fontScale = halfWidth * 2) / textWidth然后设置转换ctx.setTransform(fontScale,0,0,fontScale,r,r)(r是圆的半径或中心)并绘制文本ctx.filltext(text,0,0),并将textAlign和textBaseline 2d上下文属性设置为"center"和{分别为{1}}

该示例通过创建可在另一个画布上绘制的简单文本圈img或仅作为图像添加到DOM来显示此操作。两个属性number和radius设置要显示的数字和大小(以像素为单位)。该演示显示它正在创建并绘制到画布上,数字增加以显示它如何缩放。

"middle"