D3.js 雙按滑鼠二下加入標註文字到圖形裡(筆記用)

D3.js 雙按滑鼠二下加入標註文字到圖形裡

由於要修改為另一版本的新程式碼,因此紀錄舊程式碼如下:

 function FocusTrendChartMeasureExistData(data, maxSize, minSize) {
        d3.selectAll(".linechartMeasure g").remove();
        var linechart = d3.select(".linechartMeasure"),
            margin = { top: 20, right: 165, bottom: 30, left: 80 },
            width = parseInt(d3.select(".chart_in").style("width")) - margin.left - margin.right - 50,
            height3 = 200 - margin.top - margin.bottom,
            radius = 6;

        g = linechart.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var svg = d3.select(".linechartMeasure")
            .attr("width", width + margin.left + margin.right)
                .attr("height", height3 + margin.top + margin.bottom)
                .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var parseTime = d3.timeParse("%Y%m%d %H:%M");
        var xScale = d3.scaleTime().range([0, width]),
        yScale = d3.scaleLinear().range([height3, 0]);

        // set the colour scale
        var color = d3.scaleOrdinal(d3.schemeCategory10);

        var lineGenerator = d3.line()
                .curve(d3.curveCardinal);

        var line = lineGenerator
                .x(function (d) {
                    return xScale(d.date);
                })
                .y(function (d) {
                    return yScale(d.Size);
                });

        var jsonArray = [];
        var jsObject = $.parseJSON(data.replace(/\"/g, '"'));
        $.each(jsObject, function (index, obj) {
            jsonArray.push(obj);
        });

        var equipmentData = jsonArray.map(function (main) {
            return {
                id: main.EquipmentName,
                values: main.detailResults.map(function (detail) {
                    return {
                        date: parseTime(detail.ProcessTime),
                        Size: detail.Size
                    }
                }),
                EDCItemName: main.EDCItemName
            };
        });

        var labelName = jsonArray.map(function (main) {
            return {
                EDCItemName: main.EDCItemName
            };
        });

        //填充日期陣列
        var dataNest = d3.nest()
                   .key(function (dn) {
                       return dn.EquipmentName;
                   }).entries(jsonArray);

        var dataArray = [];
        dataNest.forEach(function (dns, i) {
            var id = dns.key;
            var value = dns.values[0];
            value.detailResults.forEach(function (detail, j) {
                dataArray.push(parseTime(detail.ProcessTime));
            })
        });

        //將日期陣列放入尺度範圍
        xScale.domain(d3.extent(dataArray, function (d) {
            return d;
        }));

        yScale.domain([
            d3.min(equipmentData, function (c) {
                if (minSize != null && !isNaN(minSize)) {
                    return minSize;
                }
                else {
                    return d3.min(c.values, function (d) {
                        return d.Size;
                    });
                }
            }),
            d3.max(equipmentData, function (c) {
                if (maxSize != null && !isNaN(maxSize)) {
                    return maxSize;
                }
                else {
                    return d3.max(c.values, function (d) {
                        return d.Size;
                    });
                }
            })
        ]);

        color.domain(equipmentData.map(function (c) {
            return c.id;
        }));

        g.append("g")
        .attr("class", "axis axis--x")
        .attr("transform", "translate(0," + height3 + ")")
        .call(d3.axisBottom(xScale));

        var edcItemName = "";
        if (labelName != null && labelName.length > 0) {
            //括號內應是檢查製程
            var checkOperationName = '@Model.ShowSearchItemToolBar.CheckOperation';
            edcItemName = labelName[0].EDCItemName + "(" + checkOperationName + ")";
        }

        g.append("g")
        .attr("class", "axis axis--y")
        .call(d3.axisLeft(yScale))
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", -46)
        .attr("dy", "0.71em")
        .attr("fill", "#000")
        .attr("font-size", 12)
        .text(edcItemName);

        var trend =
               g.selectAll(".trend")
               .data(equipmentData)
               .enter().append("g")
               .attr("class", "trend");

        trend.append("path")
               .attr("fill", "none")
               .attr("stroke", "steelblue")
               .attr("stroke-width", "1.5px")
               .attr("d", function (dns) {
                   return line(dns.values);
               })
               .style("stroke", function (dns) {
                   return color(dns.id);
               });

        equipmentData.forEach(function (dns, i) {

            var details = dns.values;

            //增加點上的文字
            svg.selectAll(".dottxt" + i)
                .data(details)
                .enter().append("text")
                .attr("class", "dottxt")
                .attr("x", function (sub) {
                    return xScale(sub.date);
                })
                .attr("y", function (sub) {
                    return yScale(sub.Size);
                })
                .style("fill", function () {
                    return color(dns.id);
                })
                .text(function (sub) {
                    return sub.Size;
                });

            //增加線上的圓點
            svg.selectAll("circle" + i)
            .data(details)
            .enter().append("circle")
                .attr("r", 4)
                .attr("cx", function (sub) {
                    return xScale(sub.date);
                })
                .attr("cy", function (sub) {
                    return yScale(sub.Size);
                })
                .style("fill", function () {
                    return color(dns.id);
                })
                .append("text")
                .attr("class", "dottxt")
                .style("fill", "#000");

            //色塊圖例
            var xNameArea = svg.append("g")
                    .attr("transform", "translate(0," + i * 20 + ")");

            xNameArea.append("rect")
                .attr("x", width + 5)
                .attr("y", 10)
                .attr("width", 19)
                .attr("height", 19)
                .attr("fill", color(dns.id));

            xNameArea.append("text")
                .attr("x", width + 25)
                .attr("y", 20)
                .attr("dy", "0.32em")
                .attr("font-size", 11)
                .text(dns.id);
        });

        var dataset = [];

        //按下加入標註文字到圖形裡
        linechart.on("dblclick", function () {
            var coords = d3.mouse(this);

            var newData = {
                x: Math.round(coords[0]),
                y: Math.round(coords[1]),
                text: "@Resource.PleaseInputRemarkName"
            };

            dataset.push(newData);

            linechart.append('text')
            .attr("id", "remarkText")
            .attr("x", newData.x)
            .attr("y", newData.y)
            .attr('text-anchor', 'middle')
            .on("mouseover", function () {
                d3.select(this).style("fill", "blue");
            })
            .text(newData.text)
            .on("click", function () {
                var p = this.parentNode;
                console.log(this, arguments);

                var xy = this.getBBox();
                var p_xy = p.getBBox();

                xy.x -= p_xy.x;
                xy.y -= p_xy.y;

                var el = d3.select(this);
                var p_el = d3.select(p);

                var frm = p_el.append("foreignObject");

                var inp = frm
                    .attr("x", xy.x)
                    .attr("y", xy.y)
                    .attr("width", 300)
                    .attr("height", 25)
                    .append("xhtml:form")
                    .append("input")
                    .attr("value", function () {
                        this.focus();
                        return newData.text;
                    })
                    .attr("style", "width: 294px;")
                    // make the form go away when you jump out (form looses focus) or hit ENTER:
                    .on("blur", function () {
                        console.log("blur", this, arguments);
                        var txt = inp.node().value;
                        newData.text = txt;
                        el.text(function (d) {
                            return newData.text;
                        });

                        // Note to self: frm.remove() will remove the entire <g> group! Remember the D3 selection logic!
                        p_el.select("foreignObject").remove();
                    })
                    .on("keypress", function () {
                        console.log("keypress", this, arguments);

                        // IE fix
                        if (!d3.event)
                            d3.event = window.event;

                        var e = d3.event;
                        if (e.keyCode == 13) {
                            if (typeof (e.cancelBubble) !== 'undefined') // IE
                                e.cancelBubble = true;

                            if (e.stopPropagation)
                                e.stopPropagation();

                            e.preventDefault();

                            var txt = inp.node().value;

                            newData.text = txt;
                            el.text(function (d) {
                                return newData.text;
                            });

                            // odd. Should work in Safari, but the debugger crashes on this instead.
                            // Anyway, it SHOULD be here and it doesn't hurt otherwise.
                            p_el.select("foreignObject").remove();
                        }
                    });
            });
        });